test: move challenge reset modal coverage to client (#68039)

Co-authored-by: sembauke <sembauke@users.noreply.github.com>
This commit is contained in:
Sem Bauke
2026-08-06 21:06:11 +02:00
committed by GitHub
parent cfab742418
commit 78f1b70aa6
2 changed files with 120 additions and 67 deletions
@@ -0,0 +1,119 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
import { beforeAll, describe, expect, it, vi } from 'vitest';
import { createStore } from '../../../redux/create-store';
import { createFiles, openModal, updateFile } from '../redux/actions';
import { render, screen } from '../../../../utils/test-utils';
import callGA from '../../../analytics/call-ga';
import ResetModal from './reset-modal';
vi.mock('../../../analytics/call-ga', () => ({
default: vi.fn()
}));
vi.mock('../../../utils/get-words');
const seedContents = '<h1>Seed content</h1>';
const changedContents = '<h1>Changed content</h1>';
const challengeFile = {
contents: seedContents,
editableRegionBoundaries: [],
ext: 'html',
fileKey: 'indexhtml',
name: 'index'
};
interface ResetModalTestState {
challenge: {
challengeFiles: Array<{ contents: string }>;
isResetting: boolean;
modal: { reset: boolean };
};
}
const setup = (props: { saveSubmissionToDB?: boolean } = {}) => {
const reduxStore = createStore();
reduxStore.dispatch(createFiles([challengeFile]));
reduxStore.dispatch(
updateFile({
fileKey: challengeFile.fileKey,
contents: changedContents,
editableRegionBoundaries: []
})
);
reduxStore.dispatch(openModal('reset'));
render(<ResetModal challengeTitle='Step 3' {...props} />, reduxStore);
return reduxStore;
};
describe('<ResetModal />', () => {
beforeAll(() => {
type ResizeObserverMockInstance = {
observe: ResizeObserver['observe'];
unobserve: ResizeObserver['unobserve'];
disconnect: ResizeObserver['disconnect'];
};
Object.defineProperty(window, 'ResizeObserver', {
writable: true,
value: vi.fn(function (
this: ResizeObserverMockInstance,
_cb: ResizeObserverCallback
) {
this.observe = vi.fn();
this.unobserve = vi.fn();
this.disconnect = vi.fn();
})
});
});
it('renders the lesson reset content and closes from the close button', async () => {
const user = userEvent.setup();
const reduxStore = setup();
const dialog = screen.getByRole('dialog', { name: 'learn.reset' });
expect(dialog).toHaveTextContent('learn.reset-warn');
expect(dialog).toHaveTextContent('learn.reset-warn-2');
expect(
screen.getByRole('button', { name: 'buttons.reset-lesson' })
).toBeInTheDocument();
expect(callGA).toHaveBeenCalledWith({
event: 'pageview',
pagePath: '/reset-modal'
});
await user.click(screen.getByText('Close'));
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
expect(reduxStore.getState().challenge.modal.reset).toBe(false);
});
it('resets challenge state and closes from the confirm button', async () => {
const user = userEvent.setup();
const reduxStore = setup();
await user.click(
screen.getByRole('button', { name: 'buttons.reset-lesson' })
);
const state = reduxStore.getState() as ResetModalTestState;
expect(state.challenge.challengeFiles[0].contents).toBe(seedContents);
expect(state.challenge.isResetting).toBe(true);
expect(state.challenge.modal.reset).toBe(false);
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
it('renders the saved-code revert content for DB-backed projects', () => {
setup({ saveSubmissionToDB: true });
const dialog = screen.getByRole('dialog', { name: 'learn.reset' });
expect(dialog).toHaveTextContent('learn.revert-warn');
expect(dialog).toHaveTextContent('learn.reset-warn-2');
expect(screen.queryByText('learn.reset-warn')).not.toBeInTheDocument();
expect(
screen.getByRole('button', { name: 'buttons.revert-to-saved-code' })
).toBeInTheDocument();
});
});
+1 -67
View File
@@ -1,6 +1,6 @@
import { execSync } from 'child_process';
import { test, expect, Page } from '@playwright/test';
import { test, expect } from '@playwright/test';
import translations from '../client/i18n/locales/english/translations.json';
import { clearEditor, focusEditor, getEditors } from './utils/editor';
@@ -21,49 +21,6 @@ interface PageData {
};
}
const expectToRenderResetModal = async (page: Page) => {
await expect(
page.getByRole('dialog', { name: translations.learn.reset })
).toBeVisible();
await expect(
page.getByRole('button', {
name: translations.buttons.close
})
).toBeVisible();
await expect(
page.getByRole('heading', {
name: translations.learn.reset
})
).toBeVisible();
await expect(
page.getByText(translations.learn['reset-warn-2'])
).toBeVisible();
};
test('should render the modal content correctly', async ({ page }) => {
await page.goto(
'/learn/responsive-web-design-v9/workshop-cat-photo-app/step-3'
);
await page.getByRole('button', { name: translations.buttons.reset }).click();
await expectToRenderResetModal(page);
await expect(
page.getByRole('button', {
name: translations.buttons['reset-lesson']
})
).toBeVisible();
await expect(
page.getByText(
'Are you sure you wish to reset this lesson (Step 3)? The code editors and tests will be reset.'
)
).toBeVisible();
});
test('User can reset challenge', async ({ page, isMobile, browserName }) => {
const initialText = ' <h2>Cat Photos</h2>';
const initialEditorText = page
@@ -199,28 +156,6 @@ test.describe('When the user is not logged in', () => {
});
});
test('should close when the user clicks the close button', async ({ page }) => {
await page.goto(
'/learn/responsive-web-design-v9/workshop-cat-photo-app/step-3'
);
await page.getByRole('button', { name: translations.buttons.reset }).click();
await expect(
page.getByRole('dialog', { name: translations.learn.reset })
).toBeVisible();
await page
.getByRole('button', {
name: translations.buttons.close
})
.click();
await expect(
page.getByRole('dialog', { name: translations.learn.reset })
).toBeHidden();
});
test('User can reset on a multi-file project', async ({
page,
isMobile,
@@ -239,7 +174,6 @@ test('User can reset on a multi-file project', async ({
await page.getByRole('button', { name: translations.buttons.revert }).click();
await expectToRenderResetModal(page);
await expect(
page.getByRole('button', {
name: translations.buttons['revert-to-saved-code']