Skip to content

Commit

Permalink
test(Operation/Jobs): add screenshot tests [YTFRONT-3772]
Browse files Browse the repository at this point in the history
  • Loading branch information
ma-efremoff committed Dec 23, 2024
1 parent 61231db commit 0a633e0
Show file tree
Hide file tree
Showing 18 changed files with 147 additions and 18 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ jobs:
steps:
- name: Run containers for 'Local'
run: |
run_local_cluster.sh --node-count 2 --ui-skip-pull true --ui-version local --yt-version stable --ui-app-installation e2e
run_local_cluster.sh --node-count 2 --ui-skip-pull true --ui-version local --yt-version stable --ui-app-installation e2e --init-operations-archive
sleep 10
- name: Checkout
uses: actions/checkout@v2
Expand Down Expand Up @@ -119,7 +119,7 @@ jobs:
- name: Run containers for 'Local as remote'
run: |
run_local_cluster.sh --stop
run_local_cluster.sh --node-count 2 --ui-skip-pull true --ui-version local --yt-version stable --ui-app-installation e2e --docker-hostname `hostname` --fqdn localhost --ui-network bridge
run_local_cluster.sh --node-count 2 --ui-skip-pull true --ui-version local --yt-version stable --ui-app-installation e2e --docker-hostname `hostname` --fqdn localhost --ui-network bridge --init-operations-archive
sleep 10
- name: Checkout
uses: actions/checkout@v2
Expand Down Expand Up @@ -160,7 +160,7 @@ jobs:
- name: Run containers for 'Local'
run: |
run_local_cluster.sh --stop
run_local_cluster.sh --node-count 2 --ui-skip-pull true --ui-version local --yt-version stable --ui-app-installation e2e
run_local_cluster.sh --node-count 2 --ui-skip-pull true --ui-version local --yt-version stable --ui-app-installation e2e --init-operations-archive
sleep 10
- name: Checkout
uses: actions/checkout@v2
Expand Down
1 change: 1 addition & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"dev": "npm run dev:app",
"dev:app": "./scripts/check-start-files.sh && npm run copy:icons && APP_ENV=${APP_ENV:-development} APP_DEV_MODE=1 NODE_OPTIONS=\"--max-http-header-size=204800 ${NODE_OPTIONS}\" app-builder dev --config ./build.app.config.ts",
"dev:localmode": "bash -c '. scripts/dev.localmode-env.sh && TVM_DISABLED=true npm run dev:app'",
"dev:localmode:cluster": "APP_INSTALLATION=${APP_INSTALLATION:-e2e} . scripts/dev.localmode-env.sh",
"dev:localmode:e2e": "APP_INSTALLATION=${APP_INSTALLATION:-e2e} npm run dev:localmode",
"dev:oss": "APP_INSTALLATION=oss npm run dev",
"docker:build": "docker build . -t ${npm_package_config_docker_image}:${npm_config_dockertag}",
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/scripts/dev.localmode-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ if [ $? -ne 0 -o "${useStop}" = "1" ]; then

echo -e "\n\nrun_local_cluster.sh is downloaded, to run your cluster use command:"

command="./run_local_cluster.sh --yt-version stable --docker-hostname $(hostname) --fqdn localhost --node-count 2 --ui-app-installation ${APP_INSTALLATION:-''}"
command="./run_local_cluster.sh --yt-version stable --docker-hostname $(hostname) --fqdn localhost --node-count 2 --ui-app-installation ${APP_INSTALLATION:-''} --init-operations-archive"

if [ "$SKIP_PULL" != "" ]; then
command="$command --ui-skip-pull true --yt-skip-pull true"
Expand Down
9 changes: 7 additions & 2 deletions packages/ui/src/ui/components/MetaTable/MetaTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import reduce_ from 'lodash/reduce';
import cn from 'bem-cn-lite';

import hammer from '../../common/hammer';
import {toClassName} from '../../utils/utils';

import Link from '../Link/Link';
import Icon from '../Icon/Icon';
Expand Down Expand Up @@ -60,7 +61,7 @@ function splitItems(items: MetaTableProps['items'], subTitles?: Array<string>) {
export default class MetaTable extends Component<MetaTableProps> {
renderKey(key: string, icon: React.ReactNode, label?: React.ReactChild) {
return (
<div className={itemBlock('key', {key})} key={key + '-key'}>
<div className={itemBlock('key', {key: toClassName(key)})} key={key + '-key'}>
{icon}
{label !== undefined ? label : hammer.format['ReadableField'](key)}
</div>
Expand All @@ -70,7 +71,11 @@ export default class MetaTable extends Component<MetaTableProps> {
renderValue(item: MetaTableItem) {
const {value, key, helpUrl, className, qa} = item;
return (
<div className={itemBlock('value', {key}, className)} key={key + '-value'} data-qa={qa}>
<div
className={itemBlock('value', {key: toClassName(key)}, className)}
key={key + '-value'}
data-qa={qa}
>
{typeof value === 'boolean' ? String(value) : value}
{helpUrl && (
<Link theme={'ghost'} url={helpUrl}>
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/ui/pages/job/JobActions/JobActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,8 @@ export default function JobActions({className}: {className?: string}) {
return (
<ErrorBoundary>
<div className={block(null, className)}>
{map_(actions, (action: Action) => (
<ActionBlock {...action} />
{map_(actions, (action: Action, index) => (
<ActionBlock key={index} {...action} />
))}
<DropdownMenu items={additionalActions} />

Expand Down
7 changes: 6 additions & 1 deletion packages/ui/src/ui/pages/job/JobGeneral/JobGeneral.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

&__header,
&__tabs {
margin-bottom: 24px;
margin-bottom: 20px;
}

&__speculative-label {
Expand Down Expand Up @@ -51,4 +51,9 @@
&__meta-breadcrumbs {
margin: -2px 0;
}

&__specification,
&__attributes {
margin-top: -10px;
}
}
3 changes: 2 additions & 1 deletion packages/ui/src/ui/pages/job/JobGeneral/JobGeneral.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ export default function JobGeneral() {
<Switch>
<Route path={`${path}/${Tab.ATTRIBUTES}`}>
<Yson
className={block('attributes')}
value={attributes}
settings={settings}
folding
Expand All @@ -297,7 +298,7 @@ export default function JobGeneral() {
<Statistics />
</Route>
<Route path={`${path}/${Tab.SPECIFICATION}`}>
<Specification jobID={jobID} />
<Specification className={block('specification')} jobID={jobID} />
</Route>
<Route path={`${path}/:tab`}>
<Placeholder />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
}
}

.checkbox {
&__checkbox {
margin-right: 16px;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {YsonDownloadButton} from '../../../../components/DownloadAttributesButto
import {getJob} from '../../../../store/selectors/job/detail';

interface SpecificationProps {
className?: string;
jobID: string;
}

Expand Down Expand Up @@ -61,20 +62,23 @@ function Toolbar({jobID}: SpecificationProps) {
return (
<div className={block('toolbar')}>
<Checkbox
className={block('checkbox')}
size="l"
content="Omit node directory"
checked={omitNodeDirectory}
onChange={handleNodeDirectoryChange}
/>

<Checkbox
className={block('checkbox')}
size="l"
content="Omit input table specs"
checked={omitInputTableSpecs}
onChange={handleInputTableSpecsChange}
/>

<Checkbox
className={block('checkbox')}
size="l"
content="Omit output table specs"
checked={omitOutputTableSpecs}
Expand All @@ -88,7 +92,7 @@ function blurByEvent(e: React.ChangeEvent<HTMLInputElement>) {
(e.target as HTMLInputElement).blur();
}

export default function Specification({jobID}: SpecificationProps) {
export default function Specification({className, jobID}: SpecificationProps) {
const dispatch = useDispatch();

const {loading, loaded, error, errorData, specification} = useSelector(
Expand All @@ -109,7 +113,7 @@ export default function Specification({jobID}: SpecificationProps) {

return (
<ErrorBoundary>
<div className={block()}>
<div className={block(null, className)}>
<div className={block('content', {loading: initialLoading})}>
{initialLoading ? (
<Loader />
Expand Down
8 changes: 8 additions & 0 deletions packages/ui/src/ui/utils/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -473,3 +473,11 @@ export function updateByLocationParams<T extends object>(
}
});
}

export function toClassName(text?: string) {
if ('string' !== typeof text) {
return undefined;
}

return text.replace(/[^-_\w\d]/g, '_');
}
83 changes: 83 additions & 0 deletions packages/ui/tests/screenshots/pages/operations/jobs.base.screen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {expect, test} from '@playwright/test';
import {E2E_OPERATION_ID, makeClusterUrl} from '../../../utils';
import {
replaceInnerHtml,
replaceInnerHtmlForDateTime,
replaceInnerHtmlForDuration,
replaceInnerHtmlForId,
replaceInnerHtmlForIsoDate,
} from '../../../utils/dom';

test('Job - Details', async ({page}) => {
test.slow();

await page.goto(makeClusterUrl(`operations/${E2E_OPERATION_ID}/jobs`));

await test.step('Details', async () => {
await page.click('.operation-detail-jobs__id-job-link');

replaceInnerHtml(page, {
'.operation-detail__events-progress-percentage': 'X.X1X%',
'.operation-detail__events-progress .g-progress': '',
});

await replaceInnerHtmlForDateTime(page, [
'.events__table-item_type_start-time .meta-table-item__time',
'.meta-table-item__value_key_started .meta-table-item__time',
'.meta-table-item__value_key_finished .meta-table-item__time',
]);

await replaceInnerHtmlForDuration(page, [
'.events__table-item_type_duration .meta-table-item__time',
'.meta-table-item__value_key_duration .meta-table-item__time',
]);

await page.waitForSelector('.meta-table-item__value_key_operation_id a');

await replaceInnerHtmlForId(page, [
'.meta-table-item__value_key_operation_id a',
'.meta-table-item__value_key_job_id .elements-ellipsis',
]);

await expect(page).toHaveScreenshot();
});

await test.step('Attributes', async () => {
await page.click('.tabs :text("Attributes")');

replaceInnerHtml(page, {
'.structured-yson-virtualized__row_key_address .structured-yson-virtualized__value':
'localhost:XXXXXx',
});

replaceInnerHtmlForIsoDate(page, [
'.structured-yson-virtualized__row_key_start_time .structured-yson-virtualized__value',
'.structured-yson-virtualized__row_key_finish_time .structured-yson-virtualized__value',
]);

replaceInnerHtmlForId(page, [
'.structured-yson-virtualized__row_key_job_id .structured-yson-virtualized__value',
'.structured-yson-virtualized__row_key_operation_id .structured-yson-virtualized__value',
'.structured-yson-virtualized__row_key_job_competition_id .structured-yson-virtualized__value',
'.structured-yson-virtualized__row_key_probing_job_competition_id .structured-yson-virtualized__value',
]);

await expect(page).toHaveScreenshot();
});

await test.step('Statistics', async () => {
await page.click('.tabs :text("Statistics")');

await page.waitForSelector('.job-statistics__table-container .job-statistics__group');

await expect(page).toHaveScreenshot();
});

await test.step('Specification', async () => {
await page.click('.tabs :text("Specification")');

await page.waitForSelector('.structured-yson-virtualized__row_key_io_config');

await expect(page).toHaveScreenshot();
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 27 additions & 5 deletions packages/ui/tests/utils/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,35 @@ export async function replaceInnerHtml(
}

export async function replaceInnerHtmlForDateTime(page: Page, selectors: Array<string>) {
const defaultDateTime = '01 Jan 1970 00:00:00';
replaceInnerHtmlForSimilarElements(page, selectors, '01 Jan 1970 00:00:00');
}

export async function replaceInnerHtmlForIsoDate(page: Page, selectors: Array<string>) {
replaceInnerHtmlForSimilarElements(page, selectors, '1970-01-01T00:00:00.000000Z');
}

export async function replaceInnerHtmlForDuration(page: Page, selectors: Array<string>) {
replaceInnerHtmlForSimilarElements(page, selectors, 'XX:XX:XX');
}

export async function replaceInnerHtmlForId(page: Page, selectors: Array<string>) {
replaceInnerHtmlForSimilarElements(page, selectors, '00000000-11111111-22222222-33333333');
}

export async function replaceInnerHtmlForSimilarElements(
page: Page,
selectors: Array<string>,
replacement: string,
) {
await replaceInnerHtml(
page,
selectors?.reduce((acc, selector) => {
acc[selector] = defaultDateTime;
return acc;
}, {} as Record<string, string>),
selectors?.reduce(
(acc, selector) => {
acc[selector] = replacement;
return acc;
},
{} as Record<string, string>,
),
);
}

Expand Down

0 comments on commit 0a633e0

Please sign in to comment.