Skip to content

Commit

Permalink
test: get rid of chrome-pwt and add e2e tests for tinder (#517)
Browse files Browse the repository at this point in the history
* test: get rid of chrome-pwt and add e2e tests for tinder
  • Loading branch information
shadowusr authored Oct 30, 2023
1 parent c45edc7 commit 512fb03
Show file tree
Hide file tree
Showing 19 changed files with 261 additions and 74 deletions.
8 changes: 6 additions & 2 deletions lib/static/components/controls/control-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface ControlButtonProps {
isDisabled?: boolean;
isRunning?: boolean;
extendClassNames?: string | string[];
dataTestId?: string | number;
}

export default class ControlButton extends Component<ControlButtonProps> {
Expand All @@ -26,7 +27,8 @@ export default class ControlButton extends Component<ControlButtonProps> {
isSuiteControl: PropTypes.bool,
isControlGroup: PropTypes.bool,
isRunning: PropTypes.bool,
extendClassNames: PropTypes.oneOfType([PropTypes.array, PropTypes.string])
extendClassNames: PropTypes.oneOfType([PropTypes.array, PropTypes.string]),
dataTestId: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
};

render(): JSX.Element {
Expand All @@ -40,7 +42,8 @@ export default class ControlButton extends Component<ControlButtonProps> {
isControlGroup,
isDisabled = false,
isRunning = false,
extendClassNames
extendClassNames,
dataTestId
} = this.props;

const className = classNames(
Expand All @@ -58,6 +61,7 @@ export default class ControlButton extends Component<ControlButtonProps> {
onClick={handler}
className={className}
disabled={isDisabled}
data-test-id={dataTestId}
>
{label}
</button>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const StrictMatchFilterInput = ({strictMatchFilter, actions}) => {
label="Strict match"
onChange={onChange}
checked={checked}
data-test-id="header-strict-match"
/>
</div>
);
Expand Down
1 change: 1 addition & 0 deletions lib/static/components/controls/test-name-filter-input.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const TestNameFilterInput = ({actions, testNameFilter: testNameFilterProp}) => {
value={testNameFilter}
placeholder="filter by test name"
onChange={onChange}
data-test-id="header-test-name-filter"
/>
);
};
Expand Down
2 changes: 1 addition & 1 deletion lib/static/components/modals/screenshot-accepter/body.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class ScreenshotAccepterBody extends Component {

return (
<div className="screenshot-accepter__title">
<span className="screenshot-accepter__test-name">{testName}</span>
<span className="screenshot-accepter__test-name" data-test-id="screenshot-accepter-test-name">{testName}</span>
<span className="screenshot-accepter__title-divider">{'/'}</span>
<span className="screenshot-accepter__browser-name">{browserName}</span>
<span className="screenshot-accepter__title-divider">{'/'}</span>
Expand Down
5 changes: 4 additions & 1 deletion lib/static/components/modals/screenshot-accepter/header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ export default class ScreenshotAccepterHeader extends Component {
isDisabled={images.length === 0}
extendClassNames="screenshot-accepter__accept-btn"
handler={this.handleScreenshotAccept}
dataTestId="screenshot-accepter-accept"
/>
<ControlButton
label="⎌ Undo"
Expand All @@ -151,6 +152,7 @@ export default class ScreenshotAccepterHeader extends Component {
isSuiteControl={true}
extendClassNames="screenshot-accepter__undo-btn"
handler={this.handleScreenUndo}
dataTestId="screenshot-accepter-undo"
/>
<ControlButton
label="Show meta"
Expand Down Expand Up @@ -185,8 +187,9 @@ export default class ScreenshotAccepterHeader extends Component {
isSuiteControl={true}
extendClassNames="screenshot-accepter__arrows-close-btn"
handler={onClose}
dataTestId="screenshot-accepter-switch-accept-mode"
/>
<ProgressBar done={acceptedImages} total={totalImages}/>
<ProgressBar done={acceptedImages} total={totalImages} dataTestId="screenshot-accepter-progress-bar"/>
</div>
</header>
</Fragment>
Expand Down
4 changes: 2 additions & 2 deletions lib/static/components/progress-bar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React from 'react';

import './index.styl';

export default ({done, total}) => {
export default ({done, total, dataTestId}) => {
const percent = (done / total).toFixed(2) * 100;

return (
<span className="progress-bar" data-content={`${done}/${total}`}>
<span className="progress-bar" data-content={`${done}/${total}`} data-test-id={dataTestId}>
<span className="progress-bar__container" style={{width: `${percent}%`}}/>
</span>
);
Expand Down
1 change: 1 addition & 0 deletions lib/static/components/section/body/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class Body extends Component {
isSuiteControl={true}
isDisabled={running}
handler={this.onTestRetry}
dataTestId="test-retry"
/>
</div>
)
Expand Down
1 change: 1 addition & 0 deletions lib/static/components/state/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class State extends Component {
isDisabled={isScreenshotAccepterDisabled}
extendClassNames="screenshot-accepter__arrows-open-btn"
handler={() => this.toggleModal()}
data-test-id="test-switch-accept-mode"
/>
</div>
);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 3 additions & 9 deletions test/func/tests/.hermione.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,20 @@ const commonConfig = getCommonConfig(__dirname);
const config = _.merge(commonConfig, {
baseUrl: `http://${serverHost}:${serverPort}/fixtures/${projectUnderTest}/report/index.html`,

browsers: {
// TODO: this is a hack to be able to have 2 sets of screenshots, for hermione-based report and pwt-based report
// currently, those have weird tiny diffs. Would be nice to figure out the cause and have common screenshots.
'chrome-pwt': {...commonConfig.browsers.chrome}
},

sets: {
common: {
files: 'common/**/*.hermione.js'
},
'common-gui': {
browsers: ['chrome'],
files: 'common-gui/**/*.hermione.js'
},
'common-tinder': {
files: 'common-tinder/**/*.hermione.js'
},
eye: {
browsers: ['chrome'],
files: 'eye/**/*.hermione.js',
},
plugins: {
browsers: ['chrome'],
files: 'plugins/**/*.hermione.js'
}
},
Expand Down
63 changes: 10 additions & 53 deletions test/func/tests/common-gui/index.hermione.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ const {promisify} = require('util');
const treeKill = promisify(require('tree-kill'));

const {PORTS} = require('../../utils/constants');
const {getTestSectionByNameSelector, getSpoilerByNameSelector, getElementWithTextSelector, hideScreenshots} = require('../utils');
const {
getTestSectionByNameSelector,
getSpoilerByNameSelector,
getElementWithTextSelector,
hideScreenshots,
runGui,
waitForFsChanges,
getFsDiffFromVcs
} = require('../utils');

const serverHost = process.env.SERVER_HOST ?? 'host.docker.internal';

Expand All @@ -18,65 +26,14 @@ const reportDir = path.join(projectDir, 'report');
const reportBackupDir = path.join(projectDir, 'report-backup');
const screensDir = path.join(projectDir, 'screens');

const runGui = async () => {
return new Promise((resolve, reject) => {
const child = childProcess.spawn('npm', ['run', 'gui'], {cwd: projectDir});

let processKillTimeoutId = setTimeout(() => {
treeKill(child.pid).then(() => {
reject(new Error('Couldn\'t start GUI: timed out'));
});
}, 3000);

child.stdout.on('data', (data) => {
if (data.toString().includes('GUI is running at')) {
clearTimeout(processKillTimeoutId);
resolve(child);
}
});

child.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});

child.on('close', (code) => {
if (code !== 0) {
reject(new Error(`GUI process exited with code ${code}`));
}
});
});
};

const getFsDiffFromVcs = (directory) => childProcess.execSync('git status . --porcelain=v2', {cwd: directory});

const waitForFsChanges = async (dirPath, condition = (output) => output.length > 0, {timeout = 1000, interval = 50} = {}) => {
let isTimedOut = false;

const timeoutId = setTimeout(() => {
isTimedOut = true;
throw new Error(`Timed out while waiting for fs changes in ${dirPath} for ${timeout}ms`);
}, timeout);

while (!isTimedOut) {
const output = getFsDiffFromVcs(dirPath);

if (condition(output)) {
clearTimeout(timeoutId);
return;
}

await new Promise(resolve => setTimeout(resolve, interval));
}
};

// These tests should not be launched in parallel
describe('GUI mode', () => {
let guiProcess;

beforeEach(async ({browser}) => {
await fs.cp(reportDir, reportBackupDir, {recursive: true});

guiProcess = await runGui();
guiProcess = await runGui(projectDir);

await browser.url(guiUrl);
await browser.$('button*=Expand all').click();
Expand Down
134 changes: 134 additions & 0 deletions test/func/tests/common-tinder/index.hermione.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
const childProcess = require('child_process');
const fs = require('fs/promises');
const path = require('path');
const treeKill = require('tree-kill');

const {PORTS} = require('../../utils/constants');
const {hideScreenshots, runGui, waitForFsChanges, getFsDiffFromVcs} = require('../utils');

const serverHost = process.env.SERVER_HOST ?? 'host.docker.internal';

const projectName = process.env.PROJECT_UNDER_TEST;
const projectDir = path.resolve(__dirname, '../../fixtures', projectName);
const guiUrl = `http://${serverHost}:${PORTS[projectName].gui}`;

const reportDir = path.join(projectDir, 'report');
const reportBackupDir = path.join(projectDir, 'report-backup');
const screensDir = path.join(projectDir, 'screens');

// These tests should not be launched in parallel
describe('Tinder mode', () => {
let guiProcess;

beforeEach(async ({browser}) => {
await fs.cp(reportDir, reportBackupDir, {recursive: true});

guiProcess = await runGui(projectDir);

await browser.url(guiUrl);
await browser.$('button*=Expand all').click();

await browser.$('button*=Switch accept mode').click();
});

afterEach(async () => {
await treeKill(guiProcess.pid);

await fs.rm(reportDir, {recursive: true, force: true, maxRetries: 3});
await fs.rename(reportBackupDir, reportDir);

childProcess.execSync('git restore .', {cwd: screensDir});
childProcess.execSync('git clean -dfx .', {cwd: screensDir});
});

describe(`accepting screenshot`, () => {
beforeEach(async ({browser}) => {
const testFullName = await browser.$('span[data-test-id="screenshot-accepter-test-name"]').getText();

const acceptButton = await browser.$('button[data-test-id="screenshot-accepter-accept"]');
await acceptButton.click();

await browser.waitUntil(async () => {
const progress = await browser.$('span[data-test-id="screenshot-accepter-progress-bar"]').getAttribute('data-content');

return progress === '1/2';
}, {interval: 100});

const switchAcceptModeButton = await browser.$('button[data-test-id="screenshot-accepter-switch-accept-mode"]');
await switchAcceptModeButton.click();

const testNameFilterInput = await browser.$('input[data-test-id="header-test-name-filter"]');

await testNameFilterInput.setValue(testFullName);
await browser.$('div[data-test-id="header-strict-match"]').click();

await waitForFsChanges(screensDir);
});

it('should create a successful retry', async ({browser}) => {
const retrySwitcher = await browser.$(`(//button[@data-test-id="retry-switcher"])[last()]`);
await hideScreenshots(browser);

await retrySwitcher.assertView('retry-switcher');
});

it('should make the test pass on next run', async ({browser}) => {
const retryButton = await browser.$('button[data-test-id="test-retry"]');

// TODO: find a correct sign to wait for. Issue is that retry button is totally clickable, but doesn't
// work right away after switch accept mode and applying filtering for some reason.
await browser.pause(500);
await retryButton.click();

await retryButton.waitForClickable({reverse: true, timeout: 10000});
await retryButton.waitForClickable({timeout: 10000});

const retrySwitcher = await browser.$(`(//button[@data-test-id="retry-switcher"])[last()]`);
await hideScreenshots(browser);

await retrySwitcher.assertView('retry-switcher');
});
});

describe(`undo accepting screenshot`, () => {
it('should leave project files intact', async ({browser}) => {
const acceptButton = await browser.$('button[data-test-id="screenshot-accepter-accept"]');
await acceptButton.click();

await browser.waitUntil(async () => {
const progress = await browser.$('span[data-test-id="screenshot-accepter-progress-bar"]').getAttribute('data-content');

return progress === '1/2';
}, {interval: 100});

await waitForFsChanges(screensDir);
const fsDiffBeforeUndo = getFsDiffFromVcs(screensDir);

const undoButton = await browser.$('button[data-test-id="screenshot-accepter-undo"]');
await undoButton.click();

await waitForFsChanges(screensDir, (output) => output.length === 0);

const fsDiffAfterUndo = getFsDiffFromVcs(screensDir);

expect(fsDiffBeforeUndo.length > 0).toBeTruthy();
expect(fsDiffAfterUndo.length === 0).toBeTruthy();
});
});

it('should show success screen after accepting all screenshots', async ({browser}) => {
const acceptButton = await browser.$('button[data-test-id="screenshot-accepter-accept"]');

for (let i = 1; i <= 2; i++) {
await acceptButton.click();

await browser.waitUntil(async () => {
const progress = await browser.$('span[data-test-id="screenshot-accepter-progress-bar"]').getAttribute('data-content');

return progress === `${i}/2`;
}, {interval: 100});
}

await expect(await browser.$('div*=All screenshots are accepted')).toBeDisplayed();
});
});
2 changes: 1 addition & 1 deletion test/func/tests/common/tests-details.hermione.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('Test details', function() {
it('should prevent details summary overflow', async ({browser}) => {
const selector =
getTestSectionByNameSelector('test with long error message') +
`//summary[.${getElementWithTextSelector('span', 'message')}/..]`;
`//summary[.${getElementWithTextSelector('span', 'stack')}/..]`;

await browser.$(selector).waitForDisplayed();
await browser.assertView('details summary', selector);
Expand Down
Loading

0 comments on commit 512fb03

Please sign in to comment.