Skip to content

Commit

Permalink
test: add tests for expo project and project cache
Browse files Browse the repository at this point in the history
  • Loading branch information
byCedric committed Mar 8, 2024
1 parent 5a4bf25 commit 565dc6a
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 2 deletions.
62 changes: 62 additions & 0 deletions src/expo/__tests__/project.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { expect } from 'chai';
import { findNodeAtLocation } from 'jsonc-parser';
import vscode from 'vscode';

import { ExpoProjectCache, findProjectFromWorkspaces } from '../project';
import { readWorkspaceFile, relativeUri } from '../../utils/file';

Check warning on line 6 in src/expo/__tests__/project.test.ts

View workflow job for this annotation

GitHub Actions / lint

`../../utils/file` import should occur before import of `../project`

describe('ExpoProjectCache', () => {
it('adds disposable to extension context', () => {
const subscriptions: any[] = [];
using _projects = stubProjectCache(subscriptions);

expect(subscriptions).to.have.length(1);
});
});

describe('findProjectFromWorkspaces', () => {
it('returns projct from workspace using relative path', () => {
using projects = stubProjectCache();
const project = findProjectFromWorkspaces(projects, './manifest');

expect(project).to.exist;
});

it('returned project contains parsed package file', () => {
using projects = stubProjectCache();
const project = findProjectFromWorkspaces(projects, './manifest');

expect(project?.package.tree).to.exist;
expect(findNodeAtLocation(project!.package.tree, ['name'])!.value).to.equal('manifest');
});

it('returned project contains parsed expo manifest file', () => {
using projects = stubProjectCache();
const project = findProjectFromWorkspaces(projects, './manifest');

expect(project?.manifest!.tree).to.exist;
expect(findNodeAtLocation(project!.manifest!.tree, ['name'])!.value).to.equal('manifest');
});
});

describe('ExpoProject', () => {
it('returns expo version from package file', async () => {
using projects = stubProjectCache();

const project = findProjectFromWorkspaces(projects, './manifest');
const workspace = vscode.workspace.workspaceFolders![0];
const packageUri = relativeUri(workspace.uri, 'manifest/package.json');
const packageFile = JSON.parse(await readWorkspaceFile(packageUri));

expect(project?.expoVersion).to.equal(packageFile.dependencies.expo);
});
});

function stubProjectCache(subscriptions: vscode.ExtensionContext['subscriptions'] = []) {
const stubProjectCache = new ExpoProjectCache({ subscriptions });

// @ts-expect-error
stubProjectCache[Symbol.dispose] = () => stubProjectCache.dispose();

return stubProjectCache as Disposable & typeof stubProjectCache;
}
19 changes: 19 additions & 0 deletions src/expo/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ export class ExpoProjectCache extends MapCacheProvider<ExpoProject> {
}

const project = new ExpoProject(root, packageFile);

// Check if there is a `app.json` or `app.config.json` file
const hasAppJson = fs.existsSync(path.join(root, 'app.json'));
const hasAppConfigJson = fs.existsSync(path.join(root, 'app.config.json'));

if (hasAppJson || hasAppConfigJson) {
project.setManifest(
fs.readFileSync(
hasAppJson ? path.join(root, 'app.json') : path.join(root, 'app.config.json'),
'utf-8'
)
);
}

this.cache.set(root, project);
return project;
}
Expand All @@ -119,6 +133,11 @@ export class ExpoProject {
return this.manifestFile;
}

get expoVersion() {
const version = jsonc.findNodeAtLocation(this.packageFile.tree, ['dependencies', 'expo']);
return version?.type === 'string' ? version.value : undefined;
}

setPackage(content: string) {
if (content === this.packageFile.content) {
return this.packageFile;
Expand Down
2 changes: 1 addition & 1 deletion src/expoDebuggers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export class ExpoDebuggersProvider implements vscode.DebugConfigurationProvider
// Resolve the target device config to inspect
const { platform, ...deviceConfig } = await resolveDeviceConfig(config, project);

featureTelemetry('debugger', `${DEBUG_TYPE}`, { platform });
featureTelemetry('debugger', `${DEBUG_TYPE}`, { platform, expoVersion: project.expoVersion });

return { ...config, ...deviceConfig };
}
Expand Down
2 changes: 1 addition & 1 deletion src/utils/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Disposable, ExtensionContext } from 'vscode';
export abstract class MapCacheProvider<V, K = string> implements Disposable {
protected cache: Map<K, V> = new Map();

constructor({ subscriptions }: ExtensionContext) {
constructor({ subscriptions }: Pick<ExtensionContext, 'subscriptions'>) {
subscriptions.push(this);
}

Expand Down
11 changes: 11 additions & 0 deletions src/utils/file.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import path from 'path';
import picomatch from 'picomatch';
import vscode from 'vscode';

/**
* Get the directory path from a user-provided file path.
Expand Down Expand Up @@ -33,3 +34,13 @@ export function fileIsExcluded(filePath: string, filesExcluded?: Record<string,
([pattern, isExcluded]) => isExcluded && picomatch(pattern)(filePath)
);
}

/** Read a workspace file through vscode's workspace API and return the string equivalent */
export async function readWorkspaceFile(uri: vscode.Uri) {
return Buffer.from(await vscode.workspace.fs.readFile(uri)).toString('utf-8');
}

/** Create a new relative URI from existing URI */
export function relativeUri(uri: vscode.Uri, relativePath: string) {
return uri.with({ path: path.join(uri.path, relativePath) });
}

0 comments on commit 565dc6a

Please sign in to comment.