Skip to content

Commit

Permalink
feat: sort projects in workspace configuration
Browse files Browse the repository at this point in the history
This commit adds sorting applied to projects found in workspace
configuration, before content is returned to the UI. Entries are sorted
using current environment locale settings.

This commit contains also changes required to start tests in context of
VSCode environment.

- implementation
- tests

Thanks!

Closes #1111
  • Loading branch information
peterblazejewicz committed Sep 24, 2021
1 parent fc4caea commit 73718cf
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 0 deletions.
5 changes: 5 additions & 0 deletions libs/server/src/lib/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,11 @@ export function toWorkspaceFormat(w: any): WorkspaceJsonConfiguration {
});
});

const sortedProjects = Object.entries(w.projects || {}).sort(
(projectA, projectB) => projectA[0].localeCompare(projectB[0])
);
w.projects = Object.fromEntries(sortedProjects);

if (w.schematics) {
renameProperty(w, 'schematics', 'generators');
}
Expand Down
22 changes: 22 additions & 0 deletions libs/vscode/nx-workspace/__mocks__/@nx-console/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const cacheJson = jest.fn();

const fileExistsSync = jest.fn();

const getOutputChannel = jest.fn(() => ({
appendLine: jest.fn(),
show: jest.fn(),
}));

const getTelemetry = jest.fn(() => ({
exception: jest.fn(),
}));

const toWorkspaceFormat = jest.fn();

export {
cacheJson,
fileExistsSync,
getOutputChannel,
getTelemetry,
toWorkspaceFormat,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const WorkspaceConfigurationStore = {
instance: {
get: jest.fn(),
},
};

export { WorkspaceConfigurationStore };
9 changes: 9 additions & 0 deletions libs/vscode/nx-workspace/__mocks__/vscode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/// <reference types="jest" />

const window = {
showErrorMessage: jest.fn(),
};

export = {
window,
};
3 changes: 3 additions & 0 deletions libs/vscode/nx-workspace/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ module.exports = {
'^.+\\.[tj]sx?$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
moduleNameMapper: {
'^@nx-console/vscode/(.+)$': '<rootDir>/libs/vscode/$1/src/index.ts',
},
coverageDirectory: '../../../coverage/libs/vscode/nx-workspace',
testEnvironment: 'node',
};
178 changes: 178 additions & 0 deletions libs/vscode/nx-workspace/src/lib/verify-workspace.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import { verifyWorkspace } from './verify-workspace';
import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration';
import * as server from '@nx-console/server';
import {
cacheJson,
fileExistsSync,
getOutputChannel,
getTelemetry,
} from '@nx-console/server';
import type { WorkspaceJsonConfiguration } from '@nrwl/devkit';
import * as vscode from 'vscode';

const mockCacheJsonFn = cacheJson as jest.MockedFunction<typeof cacheJson>;
mockCacheJsonFn.mockImplementation((filePath) => ({
json: mockWorkspace,
path: filePath,
}));

const mockStoreInstanceGetFn = WorkspaceConfigurationStore.instance
.get as jest.MockedFunction<typeof WorkspaceConfigurationStore.instance.get>;
mockStoreInstanceGetFn.mockImplementation(() => workspacePath);

const mockFileExistsSyncFn = fileExistsSync as jest.MockedFunction<
typeof fileExistsSync
>;

const originalNxConsoleServerModule = jest.requireActual('@nx-console/server');
(server.toWorkspaceFormat as unknown) =
originalNxConsoleServerModule.toWorkspaceFormat;

const mockWorkspace: WorkspaceJsonConfiguration = {
version: 2,
projects: {
Project3: {
root: 'project-three',
},
Project1: {
root: 'project-one',
},
Project2: {
root: 'project-two',
},
},
defaultProject: undefined,
generators: undefined,
cli: undefined,
};

const DefaultWorkspaceInformation = {
validWorkspaceJson: false,
workspaceType: 'nx',
json: {
projects: {},
version: 2,
},
configurationFilePath: '',
};

const workspacePath = './test/fixtures/workspace/';

describe(verifyWorkspace.name, () => {
afterEach(() => {
mockFileExistsSyncFn.mockClear();
});

describe('when Nx workspace exists', () => {
it('returns information about Nx workspace', async () => {
// arrange
mockFileExistsSyncFn.mockImplementation((filePath) =>
/workspace.json$/i.test(filePath)
);

// act
const { validWorkspaceJson, json, workspaceType, configurationFilePath } =
await verifyWorkspace();

// assert
expect(mockFileExistsSyncFn).toHaveBeenCalledTimes(1);
expect(mockFileExistsSyncFn).toHaveLastReturnedWith(true);
expect(mockStoreInstanceGetFn).toHaveBeenCalledWith(
'nxWorkspaceJsonPath',
''
);
expect(mockCacheJsonFn).toHaveBeenCalled();
expect(validWorkspaceJson).toBe(true);
expect(json).toBeTruthy();
expect(json).toEqual(mockWorkspace);
expect(workspaceType).toBe('nx');
expect(configurationFilePath).toMatch(/workspace.json$/i);
});
});

describe('when Ng workspace exists', () => {
it('returns information about Ng workspace', async () => {
// arrange
mockFileExistsSyncFn.mockImplementation((filePath) =>
/angular.json$/i.test(filePath)
);

// act
const { validWorkspaceJson, json, workspaceType, configurationFilePath } =
await verifyWorkspace();

// assert
expect(mockFileExistsSyncFn).toHaveBeenCalledTimes(2);
expect(mockFileExistsSyncFn).toHaveNthReturnedWith(1, false);
expect(mockFileExistsSyncFn).toHaveNthReturnedWith(2, true);
expect(mockStoreInstanceGetFn).toHaveBeenCalledWith(
'nxWorkspaceJsonPath',
''
);
expect(mockCacheJsonFn).toHaveBeenCalled();
expect(validWorkspaceJson).toBe(true);
expect(json).toBeTruthy();
expect(json).toEqual(mockWorkspace);
expect(workspaceType).toBe('ng');
expect(configurationFilePath).toMatch(/angular.json$/i);
});
});

describe('when workspace json does not exist', () => {
it('it shows error dialog and returns default workspace information', async () => {
// arrange
mockFileExistsSyncFn.mockImplementation(
(filePath) => !/(angular|workspace).json$/i.test(filePath)
);

(vscode.window.showErrorMessage as unknown) = jest
.fn()
.mockResolvedValue('Show Error');

// act
const result = await verifyWorkspace();

// assert
expect(mockFileExistsSyncFn).toHaveBeenCalledTimes(2);
expect(mockFileExistsSyncFn).toHaveNthReturnedWith(1, false);
expect(mockFileExistsSyncFn).toHaveNthReturnedWith(2, false);
expect(vscode.window.showErrorMessage).toHaveBeenCalledWith(
expect.any(String),
'Show Error'
);
expect(getOutputChannel).toHaveBeenCalledTimes(3);
expect(getTelemetry).toHaveBeenCalledTimes(1);
expect(result).toEqual(DefaultWorkspaceInformation);
});
});

describe('when workspace information is found', () => {
it('projects entries are sorted by entry key', async () => {
// arrange
mockFileExistsSyncFn.mockImplementationOnce(() => true);
const sortedProject = {
Project1: {
root: 'project-one',
},
Project2: {
root: 'project-two',
},
Project3: {
root: 'project-three',
},
};

// act
const {
json: { projects },
} = await verifyWorkspace();
const [project1, project2, project3] = Object.keys(projects);
const [sorted1, sorted2, sorted3] = Object.keys(sortedProject);

// assert
expect(project1).toBe(sorted1); // should be 'Project1'
expect(project2).toBe(sorted2); // should be 'Project2'
expect(project3).toBe(sorted3); // should be 'Project3'
});
});
});

0 comments on commit 73718cf

Please sign in to comment.