Skip to content

Commit

Permalink
Merge pull request #87 from joomcode/fix/mobile-emulation
Browse files Browse the repository at this point in the history
fix: mobile emulation
  • Loading branch information
uid11 authored Aug 26, 2024
2 parents c56c2fe + f15fb0b commit 913dfec
Show file tree
Hide file tree
Showing 36 changed files with 340 additions and 301 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,17 +232,18 @@ that exports the pack's config under the name `pack`.

Here are the basic fields of the pack config.

`browser: string`: browser name as a command to launch it
(like `chrome`, `chromium`, `firefox`, `webkit`, etc).

`browserFlags: string[]`: array of browser flags, like `--disable-dev-shm-usage`,
with which the browser is launched to run tests.

`browserName: BrowserName`: browser name (one of `chromium`, `firefox`, `webkit`).

`concurrency: number`: the number of browser windows in which tests will run in parallel.

`customPackProperties: CustomPackProperties`: a custom set of fields defined within the project.
These fields allow, for example, to customize the behavior of hooks for different packs.

`deviceScaleFactor: number`: device scale factor (aka `window.devicePixelRatio`).

`doAfterPack: ((liteReport: LiteReport) => CustomReportProperties | undefined)[]`:
an array of functions that will be executed, in order, after the pack completes.
The functions accept a lite report object, and can return custom report properties,
Expand Down Expand Up @@ -318,8 +319,6 @@ For example, if it is equal to three, the test will be run no more than three ti
`overriddenConfigFields: PlaywrightTestConfig | null`: if not `null`, then this value will override
fields of internal Playwright config.

`overriddenUserAgent: string | null`: if not `null`, then this value will override the browser's user agent in tests.

`packTimeout: number`: timeout (in millisecond) for the entire pack of tests (tasks).
If the test pack takes longer than this timeout, the pack will fail with the appropriate error.

Expand Down Expand Up @@ -362,6 +361,8 @@ This parameter can be overridden in the test-specific options.
If the test run takes longer than this timeout, the test fails and rerun on the next retry.
This parameter can be overridden in the test-specific options.

`userAgent: string`: `userAgent` string of browser (device) in tests.

`viewportHeight: number`: height of viewport of page in pixels.

`viewportWidth: number`: width of viewport of page in pixels.
Expand Down
9 changes: 4 additions & 5 deletions autotests/packs/allTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@ const browserFlags = [
'--ignore-certificate-errors',
];

const browser = isLocalRun ? 'chrome' : 'chromium';

const filterTestsIntoPack: FilterTestsIntoPack = ({options}) => options.meta.testId !== '13';

const overriddenUserAgent =
const userAgent =
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.35 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.35';

const packTimeoutInMinutes = 5;
Expand All @@ -44,10 +42,11 @@ const msInMinute = 60_000;
export const pack: Pack = {
ajaxRequestTimeout: 40_000,
assertionTimeout: 5_000,
browser,
browserFlags,
browserName: 'chromium',
concurrency: isLocalRun ? 1 : 2,
customPackProperties: {internalPackRunId: 0, name: 'allTests'},
deviceScaleFactor: 1,
doAfterPack,
doBeforePack,
enableHeadlessMode: true,
Expand All @@ -65,7 +64,6 @@ export const pack: Pack = {
mapLogPayloadInReport,
maxRetriesCountInDocker: 3,
overriddenConfigFields: null,
overriddenUserAgent,
packTimeout: packTimeoutInMinutes * msInMinute,
pageRequestTimeout: 30_000,
pageStabilizationInterval: 500,
Expand All @@ -81,6 +79,7 @@ export const pack: Pack = {
testFileGlobs: ['**/autotests/tests/**/*.ts'],
testIdleTimeout: 8_000,
testTimeout: 60_000,
userAgent,
viewportHeight: 1080,
viewportWidth: 1920,
waitForAllRequestsComplete: {
Expand Down
27 changes: 18 additions & 9 deletions autotests/tests/e2edReportExample/browserData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ test('correctly read data from browser', {meta: {testId: '14'}}, async () => {
console.error('error');
console.info('info');
console.log('log');
console.warn('warn');
console.warn('warning');

setTimeout(() => {
throw new Error('foo');
Expand All @@ -29,14 +29,23 @@ test('correctly read data from browser', {meta: {testId: '14'}}, async () => {
}, 32);
})();

const {error, info, log, warn} = await getBrowserConsoleMessages();

await expect(
error.length === 0 && info.length === 0 && log.length === 0 && warn.length === 0,
'getBrowserConsoleMessages read all of messages',
).eql(true);

const jsErrors = await getBrowserJsErrors();
const consoleMessages = getBrowserConsoleMessages();
const columnNumber = 12;
const url = '';

await expect(consoleMessages, 'getBrowserConsoleMessages read all of messages').eql([
{args: ['error'], location: {columnNumber, lineNumber: 3, url}, text: 'error', type: 'error'},
{args: ['info'], location: {columnNumber, lineNumber: 4, url}, text: 'info', type: 'info'},
{args: ['log'], location: {columnNumber, lineNumber: 5, url}, text: 'log', type: 'log'},
{
args: ['warning'],
location: {columnNumber, lineNumber: 6, url},
text: 'warning',
type: 'warning',
},
]);

const jsErrors = getBrowserJsErrors();

await expect(jsErrors.length === 0, 'getBrowserJsErrors read JS errors').eql(true);
});
2 changes: 1 addition & 1 deletion autotests/tests/e2edReportExample/selectorCustomMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ test('selector custom methods', {meta: {testId: '15'}}, async () => {
'[data-testid="app-navigation-retries"].findByLocatorId(app-navigation-retries-button).filterByLocatorParameter(selected, true)',
);

await click(reportPage.navigationRetriesButton);
await click(reportPage.navigationRetriesButton.nth(0));

await expect(
reportPage.testRunButton.nth(2).getLocatorParameter('status'),
Expand Down
35 changes: 19 additions & 16 deletions package-lock.json

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

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
},
"devDependencies": {
"@playwright/browser-chromium": "1.46.1",
"@types/node": "22.4.1",
"@types/node": "22.5.0",
"@typescript-eslint/eslint-plugin": "7.18.0",
"@typescript-eslint/parser": "7.18.0",
"assert-modules-support-case-insensitive-fs": "1.0.1",
Expand All @@ -42,7 +42,7 @@
"eslint-plugin-import": "2.29.1",
"eslint-plugin-simple-import-sort": "12.1.1",
"eslint-plugin-typescript-sort-keys": "3.2.0",
"husky": "9.1.4",
"husky": "9.1.5",
"prettier": "3.3.3",
"typescript": "5.5.4"
},
Expand Down
12 changes: 0 additions & 12 deletions src/actions/debug.ts

This file was deleted.

31 changes: 13 additions & 18 deletions src/actions/getBrowserConsoleMessages.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,31 @@
import {LogEventStatus, LogEventType} from '../constants/internal';
import {getConsoleMessagesFromContext} from '../context/consoleMessages';
import {log} from '../utils/log';

type ConsoleMessages = Readonly<{
error: readonly string[];
info: readonly string[];
log: readonly string[];
warn: readonly string[];
}>;
import type {ConsoleMessage} from '../types/internal';

type Options = Readonly<{
showMessagesInLog?: boolean;
}>;

const logMessage = 'Get browser console messages';

/**
* Returns an object that contains messages output to the browser console.
*/
export const getBrowserConsoleMessages = (options: Options = {}): Promise<ConsoleMessages> => {
export const getBrowserConsoleMessages = (options: Options = {}): readonly ConsoleMessage[] => {
const {showMessagesInLog = false} = options;
const consoleMessages = getConsoleMessagesFromContext();

if (showMessagesInLog === false) {
log('Get browser console messages', LogEventType.InternalAction);
log(logMessage, LogEventType.InternalAction);
} else {
const logEventStatus = consoleMessages.some(({type}) => type === 'error')
? LogEventStatus.Failed
: LogEventStatus.Passed;

// TODO
return Promise.resolve({error: [], info: [], log: [], warn: []});
log(logMessage, {consoleMessages, logEventStatus}, LogEventType.InternalAction);
}

return Promise.resolve({error: [], info: [], log: [], warn: []}).then((messages) => {
const logEventStatus =
messages.error.length > 0 ? LogEventStatus.Failed : LogEventStatus.Passed;

log('Got browser console messages', {logEventStatus, messages}, LogEventType.InternalAction);

return messages;
});
return consoleMessages;
};
17 changes: 6 additions & 11 deletions src/actions/getBrowserJsErrors.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
import {LogEventStatus, LogEventType} from '../constants/internal';
import {getJsErrorsFromContext} from '../context/jsError';
import {log} from '../utils/log';

import type {BrowserJsError} from '../types/internal';

type Options = Readonly<{
showErrorsInLog?: boolean;
}>;

/**
* Get browser JS errors.
*/
export const getBrowserJsErrors = (options: Options = {}): Promise<readonly BrowserJsError[]> => {
export const getBrowserJsErrors = (options: Options = {}): readonly Error[] => {
const {showErrorsInLog = false} = options;
const jsErrors = getJsErrorsFromContext();

if (showErrorsInLog === false) {
log('Get browser JS errors', LogEventType.InternalAction);

return Promise.resolve([]);
}

// TODO
return Promise.resolve([]).then((jsErrors = []) => {
} else {
const logEventStatus = jsErrors.length > 0 ? LogEventStatus.Failed : LogEventStatus.Passed;

log('Got browser JS errors', {jsErrors, logEventStatus}, LogEventType.InternalAction);
}

return jsErrors;
});
return jsErrors;
};
2 changes: 1 addition & 1 deletion src/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export {
} from './asserts';
export {clearUpload} from './clearUpload';
export {click} from './click';
export {debug} from './debug';
export {deleteCookies} from './deleteCookies';
export {dispatchEvent} from './dispatchEvent';
export {doubleClick} from './doubleClick';
Expand All @@ -28,6 +27,7 @@ export {
navigateToPage,
reloadPage,
} from './pages';
export {pause} from './pause';
export {pressKey} from './pressKey';
export {resizeWindow} from './resizeWindow';
export {scroll} from './scroll';
Expand Down
12 changes: 6 additions & 6 deletions src/actions/navigateToUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import {LogEventType} from '../constants/internal';
import {getPlaywrightPage} from '../useContext';
import {log} from '../utils/log';

import type {Page} from '@playwright/test';

import type {Url} from '../types/internal';

type Options = Readonly<{
skipLogs?: boolean;
}>;
type Options = Readonly<{skipLogs?: boolean} & Parameters<Page['goto']>[1]>;

/**
* Navigate to the `url` (without waiting of interface stabilization).
Expand All @@ -15,14 +15,14 @@ export const navigateToUrl = async (url: Url, options: Options = {}): Promise<vo
const {skipLogs = false} = options;

if (skipLogs !== true) {
log(`Will navigate to the url ${url}`, LogEventType.InternalAction);
log(`Will navigate to the url ${url}`, options, LogEventType.InternalAction);
}

const page = getPlaywrightPage();

await page.goto(url);
await page.goto(url, options);

if (skipLogs !== true) {
log(`Navigation to the url ${url} completed`, LogEventType.InternalAction);
log(`Navigation to the url ${url} completed`, options, LogEventType.InternalAction);
}
};
14 changes: 14 additions & 0 deletions src/actions/pause.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {LogEventType} from '../constants/internal';
import {getPlaywrightPage} from '../useContext';
import {log} from '../utils/log';

/**
* Pauses the test and switches to the step-by-step execution mode.
*/
export const pause = (): Promise<void> => {
log('Pause', LogEventType.InternalAction);

const page = getPlaywrightPage();

return page.pause();
};
Loading

0 comments on commit 913dfec

Please sign in to comment.