Skip to content

Commit

Permalink
Added widget template with unit tests
Browse files Browse the repository at this point in the history
fixed #103

Contributed on behalf of STMicroelectronics

Signed-off-by: Jonas Helming <[email protected]>
  • Loading branch information
JonasHelming authored Jun 8, 2021
1 parent 794ad7d commit e75778e
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 7 deletions.
37 changes: 33 additions & 4 deletions src/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import Base = require('yeoman-generator');
enum ExtensionType {
HelloWorld = 'hello-world',
Widget = 'widget',
WidgetWithUnitTests = 'widget-with-unittest',
LabelProvider = 'labelprovider',
TreeEditor = 'tree-editor',
Empty = 'empty',
Expand Down Expand Up @@ -47,6 +48,10 @@ module.exports = class TheiaExtension extends Base {
standalone: boolean
dependencies: string
browserDevDependencies: string
devdependencies: string
scripts: string
rootscripts: string
containsTests: boolean
};

constructor(args: string | string[], options: any) {
Expand Down Expand Up @@ -149,6 +154,7 @@ module.exports = class TheiaExtension extends Base {
choices: [
{ value: ExtensionType.HelloWorld, name: 'Hello World' },
{ value: ExtensionType.Widget, name: 'Widget' },
{ value: ExtensionType.WidgetWithUnitTests, name: 'Widget with Unit Tests' },
{ value: ExtensionType.LabelProvider, name: 'LabelProvider' },
{ value: ExtensionType.TreeEditor, name: 'TreeEditor' },
{ value: ExtensionType.Backend, name: 'Backend Communication' },
Expand Down Expand Up @@ -193,12 +199,17 @@ module.exports = class TheiaExtension extends Base {
lernaVersion: options["lerna-version"],
backend: options["extensionType"] === ExtensionType.Backend
}
this.params.dependencies = '';
this.params.browserDevDependencies = '';
if (this.params.extensionType === ExtensionType.TreeEditor) {
this.params.dependencies = `,\n "@theia/editor": "${this.params.theiaVersion}",\n "@theia/filesystem": "${this.params.theiaVersion}",\n "@theia/workspace": "${this.params.theiaVersion}",\n "@eclipse-emfcloud/theia-tree-editor": "latest",\n "uuid": "^3.3.2"`;
this.params.browserDevDependencies = `,\n "node-polyfill-webpack-plugin": "latest"`;
} else {
this.params.dependencies = '';
this.params.browserDevDependencies = '';
}
if (this.params.extensionType === ExtensionType.WidgetWithUnitTests) {
this.params.devdependencies = `,\n "@testing-library/react": "^11.2.7",\n "@types/jest": "^26.0.20",\n "jest": "^26.6.3",\n "ts-node": "^9.1.1",\n "ts-jest": "^26.5.6"`;
this.params.scripts = `,\n "test": "jest --config configs/jest.config.ts"`;
this.params.rootscripts =`,\n "test": "cd ${this.params.extensionPath} && yarn test"`;
this.params.containsTests = true;
}
options.params = this.params
if (!options.standalone) {
Expand Down Expand Up @@ -294,7 +305,7 @@ module.exports = class TheiaExtension extends Base {
}

/** widget */
if (this.params.extensionType === ExtensionType.Widget) {
if (this.params.extensionType === ExtensionType.Widget||this.params.extensionType === ExtensionType.WidgetWithUnitTests) {
this.fs.copyTpl(
this.templatePath('widget/frontend-module.ts'),
this.extensionPath(`src/browser/${this.params.extensionPath}-frontend-module.ts`),
Expand All @@ -321,6 +332,24 @@ module.exports = class TheiaExtension extends Base {
{ params: this.params }
);
}
/** widget with unit test */
if (this.params.extensionType === ExtensionType.WidgetWithUnitTests) {
this.fs.copyTpl(
this.templatePath('widget/__tests__/widget.test.ts'),
this.extensionPath(`src/browser/__tests__/${this.params.extensionPath}-widget.test.ts`),
{ params: this.params }
);
this.fs.copyTpl(
this.templatePath('widget/__tests__/mock-objects/mock-message-service.ts'),
this.extensionPath(`src/browser/__tests__/mock-objects/mock-message-service.ts`),
{ params: this.params }
);
this.fs.copyTpl(
this.templatePath('widget/configs/jest.config.ts'),
this.extensionPath(`configs/jest.config.ts`),
{ params: this.params }
);
}

/** backend */
if (this.params.extensionType === ExtensionType.Backend) {
Expand Down
12 changes: 12 additions & 0 deletions templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ Open http://localhost:3000 in the browser.
yarn start

*or:* launch `Start Electron Backend` configuration from VS code.

<%if(params.containsTests){%>
## Running the tests

yarn test

*or* run the tests of a specific package with

cd <%= params.extensionPath %>
yarn test

<%}%>
## Developing with the browser example

Start watching all packages, including `browser-app`, of your application with
Expand Down
4 changes: 2 additions & 2 deletions templates/extension-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@
},
"devDependencies": {
"rimraf": "latest",
"typescript": "latest"
"typescript": "latest"<% if (params.devdependencies) { %><%- params.devdependencies %><% } %>
},
"scripts": {
"prepare": "yarn run clean && yarn run build",
"clean": "rimraf lib",
"build": "tsc",
"watch": "tsc -w"
"watch": "tsc -w"<% if (params.scripts) { %><%- params.scripts %><% } %>
},
"theiaExtensions": [
{
Expand Down
2 changes: 1 addition & 1 deletion templates/root-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"rebuild:electron": "theia rebuild:electron",
"start:browser": "yarn rebuild:browser && yarn --cwd browser-app start",
"start:electron": "yarn rebuild:electron && yarn --cwd electron-app start",
"watch": "lerna run --parallel watch"
"watch": "lerna run --parallel watch"<% if (params.rootscripts) { %><%- params.rootscripts %><% } %>
},
"devDependencies": {
"lerna": "<%= params.lernaVersion %>"
Expand Down
64 changes: 64 additions & 0 deletions templates/widget/__tests__/mock-objects/mock-message-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { injectable, inject } from 'inversify';
import { Message, MessageClient, MessageOptions, MessageType, ProgressMessage, ProgressUpdate } from '@theia/core/lib/common/message-service-protocol';
import { CancellationToken, MessageService } from '@theia/core';

@injectable()
export class MockMessageService extends MessageService{

constructor(
@inject(MessageClient) protected readonly client: MessageClient
) { super(client) }

logWasCalled: boolean = false;
infoWasCalled: boolean = false;
warnWasCalled: boolean = false;
errorWasCalled: boolean = false;

log<T extends string>(message: string, ...actions: T[]): Promise<T | undefined>;
log<T extends string>(message: string, options?: MessageOptions, ...actions: T[]): Promise<T | undefined>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
log(message: string, ...args: any[]): Promise<string | undefined> {
this.logWasCalled = true;
return this.processMessage(MessageType.Log, message, args);
}

info<T extends string>(message: string, ...actions: T[]): Promise<T | undefined>;

info<T extends string>(message: string, options?: MessageOptions, ...actions: T[]): Promise<T | undefined>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
info(message: string, ...args: any[]): Promise<string | undefined> {
this.infoWasCalled = true;
return this.processMessage(MessageType.Info, message, args);
}

warn<T extends string>(message: string, ...actions: T[]): Promise<T | undefined>;
warn<T extends string>(message: string, options?: MessageOptions, ...actions: T[]): Promise<T | undefined>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
warn(message: string, ...args: any[]): Promise<string | undefined> {
this.warnWasCalled = true;
return this.processMessage(MessageType.Warning, message, args);
}

error<T extends string>(message: string, ...actions: T[]): Promise<T | undefined>;
error<T extends string>(message: string, options?: MessageOptions, ...actions: T[]): Promise<T | undefined>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
error(message: string, ...args: any[]): Promise<string | undefined> {
this.errorWasCalled = true;
return this.processMessage(MessageType.Error, message, args);
}
}

@injectable()
export class MockMessageClient {

showMessage(message: Message): Promise<string | undefined> {
return Promise.resolve(undefined);
}

showProgress(progressId: string, message: ProgressMessage, cancellationToken: CancellationToken): Promise<string | undefined> {
return Promise.resolve(undefined);
}
reportProgress(progressId: string, update: ProgressUpdate, message: ProgressMessage, cancellationToken: CancellationToken): Promise<void> {
return Promise.resolve(undefined);
}
}
33 changes: 33 additions & 0 deletions templates/widget/__tests__/widget.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'reflect-metadata';
import { MessageClient, MessageService } from '@theia/core';
import { ContainerModule, Container } from 'inversify';
import { MockMessageClient, MockMessageService } from './mock-objects/mock-message-service';
import { <%= params.extensionPrefix %>Widget } from '../<%= params.extensionPath %>-widget';
import { render } from '@testing-library/react'

describe('widget extension unit tests', () => {

let widget: any;

beforeEach(async () => {
const module = new ContainerModule( bind => {
bind(MessageClient).to(MockMessageClient).inSingletonScope();
bind(MessageService).to(MockMessageService).inSingletonScope();
bind(<%= params.extensionPrefix %>Widget).toSelf();
});
const container = new Container();
container.load(module);
widget = container.resolve<<%= params.extensionPrefix %>Widget>(<%= params.extensionPrefix %>Widget);
});

it('should render react node correctly', async () => {
const element = render(widget.render());
expect(element.queryByText('Display Message')).toBeTruthy();
});

it('should inject the message service', async () => {
widget.displayMessage();
expect(widget.messageService.infoWasCalled).toBe(true);
});

});
10 changes: 10 additions & 0 deletions templates/widget/configs/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { Config } from '@jest/types';

export default async (): Promise<Config.InitialOptions> => ({
preset: 'ts-jest',
testMatch: ['**.test.ts'],
rootDir: '../',
transform: {
'^.+\\.(ts)$': 'ts-jest',
}
});

0 comments on commit e75778e

Please sign in to comment.