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

test: get rid of chrome-pwt and add e2e tests for tinder #517

Merged
merged 4 commits into from
Oct 30, 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
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});
shadowusr marked this conversation as resolved.
Show resolved Hide resolved
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();
shadowusr marked this conversation as resolved.
Show resolved Hide resolved

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);
shadowusr marked this conversation as resolved.
Show resolved Hide resolved
await retryButton.click();

await retryButton.waitForClickable({reverse: true, timeout: 10000});
shadowusr marked this conversation as resolved.
Show resolved Hide resolved
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();
shadowusr marked this conversation as resolved.
Show resolved Hide resolved
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')}/..]`;
shadowusr marked this conversation as resolved.
Show resolved Hide resolved

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