Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[patch] [TestOps] fix for watcher #54

Merged
merged 2 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: '18.x'
node-version: '18.12.0'
registry-url: 'https://registry.npmjs.org'

- uses: volta-cli/action@v4
Expand Down
9 changes: 3 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
## Change Log
### 1.0.0
- [TestOps] [BREAKING CHANGE] - videos will be uploaded once for spec and uploaded to an after hook named `video`.
This should keep more storage, since video file is one. It will be available in all tests from the spec.<br>
If you used env var `allureResultsWatchPath` previously from this version it is removed.
You need to specify only `allureResults` now and tell testops to watch it.
### 0.12.1
- [TestOps] watcher improvements - realtime results for all tests

### 0.12.0
- [TestOps] watcher imrovements - realtime results for passed tests
- [TestOps] watcher improvements - realtime results for passed tests

### 0.11.0
- [#35] issue - add possibility to skip hooks by env var `allureSkipSteps`
Expand Down
31 changes: 16 additions & 15 deletions README.pack.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default defineConfig({
allureAttachRequests: true,
allureCompactAttachments: 'false',
allureResults: 'allure-results', // for test results to write
allureResultsWatchPath: 'allure-results/watch',
allureSkipCommands: '', // separated comma
// allureSkipSteps: '"after each" hook*,"before each" hook*,"before all" hook', // separated comma
allureAddVideoOnPass: 'true',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"publish:patch": "export ver=$(semver $(npm show . version) --increment -i patch) && npm run publishPack && npm run postpublish",
"publish:minor": "export ver=$(semver $(npm show . version) --increment -i minor) && npm run publishPack && npm run postpublish",
"publish:major": "export ver=$(semver $(npm show . version) --increment -i major) && npm run publishPack && npm run postpublish",
"publish:pack": "export ver=\"0.0.2-alpha-2\" && npm run publishPack && npm run postpublish",
"publish:pack": "export ver=\"1.0.1\" && npm run publishPack && npm run postpublish",
"postpublish": "git tag v$ver"
},
"overrides": {
Expand Down
186 changes: 121 additions & 65 deletions src/plugins/allure-reporter-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,35 @@
AllureRuntime,
AllureStep,
AllureTest,
Attachment,
ExecutableItem,
ExecutableItemWrapper,
FixtureResult,
Status,
StatusDetails,
TestResult,
} from 'allure-js-commons';
import getUuid from 'uuid-by-string';
import getUuidByString from 'uuid-by-string';
import { parseAllure } from 'allure-js-parser';
import { copyFile, copyFileSync, existsSync, mkdirSync, readFile, readFileSync, writeFile, writeFileSync } from 'fs';
import { copyFileSync, existsSync, mkdirSync, readFile, readFileSync, writeFileSync } from 'fs';
import path, { basename } from 'path';
import glob from 'fast-glob';
import { ReporterOptions } from './allure';
import Debug from 'debug';
import { GlobalHooks } from './allure-global-hook';
import { AllureTaskArgs, LabelName, Stage, Status, StatusType, UNKNOWN } from './allure-types';
import { delay, extname, packageLog } from '../common';
import { AllureTaskArgs, LabelName, Stage, StatusType, UNKNOWN } from './allure-types';
import { extname, packageLog } from '../common';
import type { ContentType } from '../common/types';
import { randomUUID } from 'crypto';
import {
copyAttachments,
copyFileCp,
copyTest,
mkdirSyncWithTry,
waitWhileCondition,
writeResultFile,
} from './fs-tools';

const beforeEachHookName = '"before each" hook';
const beforeAllHookName = '"before all" hook';
Expand All @@ -37,24 +47,93 @@
debug(args);
};

const writeTestFile = (testFile: string, content: string, callBack: () => void) => {
writeFile(testFile, content, errWrite => {
if (errWrite) {
log(`error test file ${errWrite.message} `);
const createNewContentForContainer = (nameAttAhc: string, existingContents: Buffer, ext: string, specname: string) => {
const containerJSON = JSON.parse(existingContents.toString());

const after: ExecutableItem = {
name: 'video',
attachments: [
{
name: `${specname}${ext}`,
type: 'video/mp4',
source: nameAttAhc,
},
],
parameters: [],
start: Date.now(),
stop: Date.now(),
status: Status.PASSED,
statusDetails: {},
stage: Stage.FINISHED,
steps: [],
};

if (!containerJSON.afters) {
containerJSON.afters = [];
}

containerJSON.afters.push(after);

return containerJSON;
};

return;
/**
* Will copy test results and all attachments to watch folder
* for results to appear in TestOps
* @param input
* @param allureResultsWatch
*/
const copyFileToWatch = async (
input: { test: string; attachments: { name: string; type: string; source: string }[] },
allureResultsWatch: string,
) => {
const { test: allureResultFile, attachments } = input;
const allureResults = path.dirname(allureResultFile);

if (allureResults === allureResultsWatch) {
log(`afterSpec allureResultsWatch the same as allureResults ${allureResults}, will not copy`);

return;
}
mkdirSyncWithTry(allureResultsWatch);

log(`allureResults: ${allureResults}`);
log(`allureResultsWatch: ${allureResultsWatch}`);
log(`attachments: ${JSON.stringify(attachments)}`);

await copyAttachments(attachments, allureResultsWatch, allureResultFile);
await copyTest(allureResultFile, allureResultsWatch);
};

/**
* Get all attachments for test to move them to watch folder
* @param item test item
*/
const getAllAttachments = (item: ExecutableItem) => {
const attachmentsResult: Attachment[] = [];

const inner = (steps: ExecutableItem[], accumulatedRes: Attachment[]): Attachment[] => {
if (steps.length === 0) {
return accumulatedRes;
}
log(`write test file done ${testFile} `);
callBack();
});

const [first, ...rest] = steps;
const newRes = [...accumulatedRes, ...first.attachments];

return inner(rest, newRes);
};

return inner(item.steps, attachmentsResult);
};

// all tests for session
const allTests: { specRelative: string | undefined; fullTitle: string; uuid: string; mochaId: string }[] = [];

export class AllureReporter {
// todo config
private showDuplicateWarn: boolean;
private allureResults: string;
private allureResultsWatch: string;
private allureAddVideoOnPass: boolean;
private allureSkipSteps: RegExp[];
private videos: string;
Expand All @@ -78,6 +157,7 @@
constructor(opts: ReporterOptions) {
this.showDuplicateWarn = opts.showDuplicateWarn;
this.allureResults = opts.allureResults;
this.allureResultsWatch = opts.techAllureResults;
this.allureAddVideoOnPass = opts.allureAddVideoOnPass;
this.videos = opts.videos;
this.screenshots = opts.screenshots;
Expand Down Expand Up @@ -408,14 +488,14 @@
* @param arg {path: string}
*/
async attachVideoToContainers(arg: { path: string }) {
// this happens after test has already finished
// this happens after test and suites have already finished
const { path: videoPath } = arg;
log(`attachVideoToTests: ${videoPath}`);
const ext = '.mp4';
const specname = basename(videoPath, ext);
log(specname);

// when video uploads everything is uploaded already(TestOps) except containers
// when video uploads everything is uploaded already (TestOps) except containers
const res = parseAllure(this.allureResults);

const tests = res
Expand All @@ -431,15 +511,20 @@

let doneFiles = 0;

readFile(videoPath, (errVideo, _contentVideo) => {
readFile(videoPath, errVideo => {
if (errVideo) {
console.error(`Could not read video: ${errVideo}`);

return;
}

testsAttach.forEach(test => {
const containerFile = `${this.allureResults}/${test.parent?.uuid}-container.json`;
if (!test.parent) {
console.error(`not writing videos since test has no parent suite: ${test.fullName}`);

return;
}
const containerFile = `${this.allureResults}/${test.parent.uuid}-container.json`;
log(`ATTACHING to container: ${containerFile}`);

readFile(containerFile, (err, contents) => {
Expand All @@ -448,71 +533,34 @@

return;
}
const testCon = JSON.parse(contents.toString());
const uuid = randomUUID();

const nameAttAhc = `${uuid}-attachment${ext}`;
const newPath = path.join(this.allureResults, nameAttAhc);
const newContentJson = createNewContentForContainer(nameAttAhc, contents, ext, specname);
const newContent = JSON.stringify(newContentJson);

const after = {
name: 'video',
attachments: [
{
name: `${specname}${ext}`,
type: 'video/mp4',
source: nameAttAhc,
},
],
parameters: [],
start: Date.now(),
stop: Date.now(),
status: 'passed',
statusDetails: {},
stage: 'finished',
steps: [],
const writeContainer = () => {
log(`write result file ${containerFile} `);
writeResultFile(containerFile, newContent, () => {
doneFiles = doneFiles + 1;
});
};

if (!testCon.afters) {
testCon.afters = [after];
} else {
testCon.afters.push(after);
}

if (existsSync(newPath)) {
log(`not writing! video file ${newPath} `);

writeTestFile(containerFile, JSON.stringify(testCon), () => {
doneFiles = doneFiles + 1;
});
log(`not writing video, file already exist in path ${newPath} `);
writeContainer();

return;
}

log(`write video file ${newPath} `);
copyFile(videoPath, newPath, errCopy => {
if (errCopy) {
log(`error copy file ${errCopy.message} `);

return;
}
log(`write test file ${containerFile} `);
writeTestFile(containerFile, JSON.stringify(testCon), () => {
doneFiles = doneFiles + 1;
});
copyFileCp(videoPath, newPath, false, () => {
writeContainer();
});
});
});
});
const started = Date.now();
const timeout = 10000;

while (doneFiles < testsAttach.length) {
if (Date.now() - started >= timeout) {
console.error(`Could not write all video attachments in ${timeout}ms`);
break;
}
await delay(100);
}
await waitWhileCondition(() => doneFiles < testsAttach.length);
}

endGroup() {
Expand Down Expand Up @@ -659,7 +707,7 @@
}

const group = this.currentGroup;
const test = group!.startTest(title);

Check warning on line 710 in src/plugins/allure-reporter-plugin.ts

View workflow job for this annotation

GitHub Actions / build

Forbidden non-null assertion

Check warning on line 710 in src/plugins/allure-reporter-plugin.ts

View workflow job for this annotation

GitHub Actions / build

Forbidden non-null assertion

allTests.push({ specRelative: this.currentSpec?.relative, fullTitle, mochaId: id, uuid: test.uuid }); // to show warning
this.tests.push(test);
Expand Down Expand Up @@ -752,7 +800,7 @@
}
}

endTest(arg: AllureTaskArgs<'testEnded'>): void {
async endTest(arg: AllureTaskArgs<'testEnded'>): Promise<void> {
const { result, details } = arg;
const storedStatus = this.testStatusStored;
const storedDetails = this.testDetailsStored;
Expand Down Expand Up @@ -788,6 +836,9 @@

this.applyGroupLabels();
const uid = this.currentTest.uuid;

//const resAtt: Attachment[] = [...this.currentTest.wrappedItem.attachments];
const attachments = getAllAttachments(this.currentTest.wrappedItem);
this.currentTest.endTest();
this.tests.pop();
this.descriptionHtml = [];
Expand All @@ -807,6 +858,11 @@
}
};
waitResultWritten(this.allureResults, `${this.allureResults}/${uid}-result.json`);

// move to watch

log('testEnded: will move result to watch folder');
await copyFileToWatch({ test: `${this.allureResults}/${uid}-result.json`, attachments }, this.allureResultsWatch);
}

startStep(arg: AllureTaskArgs<'stepStarted'>) {
Expand Down
Loading
Loading