Skip to content

Commit

Permalink
Merge pull request #206 from mate-academy/fix-layoutDOM-test-command-…
Browse files Browse the repository at this point in the history
…and-add-report-service

[LayoutDOM]: fix test command and add reusable report service
  • Loading branch information
sergii-nosachenko authored Jan 24, 2024
2 parents f5fc610 + 81b5da4 commit e553680
Show file tree
Hide file tree
Showing 11 changed files with 3,418 additions and 124 deletions.
2 changes: 1 addition & 1 deletion mate-scripts/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion mate-scripts/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mate-academy/scripts",
"version": "1.2.12",
"version": "1.3.2",
"description": "Scripts to init, run, test, deploy Mate academy homework projects",
"main": "bin/mateScripts.js",
"scripts": {
Expand Down
178 changes: 168 additions & 10 deletions mate-scripts/src/commands/Test.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { BackstopService, JestService } from '../services';
import { Command } from './Command';
import { CypressService, StartServer } from '../services/Cypress.service';
import { StartCommand } from './Start.command';
import { ReportService } from '../services/Report.service';
import { Spinner } from '../tools/Spinner';

export interface TestOptions {
open: boolean;
Expand All @@ -17,8 +19,12 @@ export class TestCommand extends Command {

private readonly cypress = new CypressService(this.rootDir);

private readonly report = new ReportService(this.rootDir);

private readonly startCommand = this.child(StartCommand);

private readonly spinner = new Spinner();

private showLogs?: boolean;

protected common(): void {
Expand Down Expand Up @@ -64,7 +70,121 @@ export class TestCommand extends Command {
};

protected layoutDOM = async (options: TestOptions) => {
await this.cypress.run(options);
const { showLogs } = options;

this.showLogs = showLogs;

const { jest } = this.config.tests;

const startServer: StartServer = async () => {
const freePort = await TestCommand.getPort();

const childProcess = this.startCommand.layout(
{ shouldShowInternalLogs: showLogs, open: false, port: freePort },
true,
);

if (!childProcess.stdout) {
await kill(childProcess.pid);

throw new Error('Unexpected error: child stdout is null');
}

let testsStarted = false;

const serverStartedPromise = new Promise<void>(
(resolve, reject) => {
if (!childProcess.stdout) {
kill(childProcess.pid)
.then(() => {
this.log('CHILD PROCESS KILLED: No stdout');
})
.catch((error) => {
this.log('CHILD PROCESS NOT KILLED: No stdout');

throw error;
})
.finally(() => {
reject(new Error('Unexpected error: child stdout is null'));
});

return;
}

const stdoutListener = (data: any) => {
if (testsStarted || !data.toString().includes('Server running')) {
return;
}

testsStarted = true;

childProcess.stdout?.off('data', stdoutListener);

resolve();
};

childProcess.stdout.on('data', stdoutListener);
},
);

const timeoutPromise = new Promise<void>((resolve, reject) => {
setTimeout(async () => {
if (!testsStarted) {
try {
await kill(childProcess.pid);

this.log('CHILD PROCESS KILLED: Timeout');
} catch (error) {
this.log('CHILD PROCESS NOT KILLED: Timeout');
}

reject(new Error('Server not started after 30 seconds'));
} else {
resolve();
}
}, 30000);
});

await Promise.race([
serverStartedPromise,
timeoutPromise,
]);

return {
port: freePort,
stop: async () => {
try {
await kill(childProcess.pid);

this.log('CHILD PROCESS KILLED: Stop');
} catch (error) {
this.log('CHILD PROCESS NOT KILLED: Stop');
}
},
};
};

await this.executeWithReportAndSpinner(async () => {
let testsFailed = false;

if (jest) {
const { exitCode } = await this.jest.onceAsync();

testsFailed = exitCode !== 0;
}

const failedCasesCount = await this.cypress.run({
...options,
e2e: true,
startServer,
});

testsFailed = testsFailed || failedCasesCount > 0;

return testsFailed
? 1
: 0;
});
};

protected react = async (options: TestOptions) => {
Expand Down Expand Up @@ -167,15 +287,25 @@ export class TestCommand extends Command {
};
};

if (cypress || cypressComponents) {
await this.cypress.run({
...options,
e2e: cypress,
components: cypressComponents,
startServer,
});
}
};
await this.executeWithReportAndSpinner(async () => {
let testsFailed = false;

if (cypress || cypressComponents) {
const failedCasesCount = await this.cypress.run({
...options,
e2e: cypress,
components: cypressComponents,
startServer,
});

testsFailed = failedCasesCount > 0;
}

return testsFailed
? 1
: 0;
});
}

protected reactTypescript = async (options: TestOptions) => {
await this.react(options);
Expand All @@ -198,4 +328,32 @@ export class TestCommand extends Command {
console.log(...args);
}
}

async executeWithReportAndSpinner(
callback: () => Promise<number>,
) {
let exitCode = 0;

try {
await this.report.runBeforeTests();

if (!this.showLogs) {
this.spinner.start();
}

exitCode = await callback();
} catch (error) {
this.log('TESTS EXECUTION FAILED', error);

process.exit(1);
} finally {
this.spinner.stop();

await this.report.runAfterTests();
}

if (exitCode > 0) {
process.exit(1);
}
}
}
2 changes: 1 addition & 1 deletion mate-scripts/src/controllers/lint.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ export const lintController: Controller<LintOptions> = (
}

return {
styles, html, bem, javascript, files: ensuredFiles, htmlLint
styles, html, bem, javascript, files: ensuredFiles, htmlLint,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ class Redelivery {

const currentDeliveries = await this.getNextDeliveries(
hookId,
last ? last.id : undefined,
last
? last.id
: undefined,
);

log(`Fetched Deliveries ${count} time`);
Expand Down
Loading

0 comments on commit e553680

Please sign in to comment.