mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 10:22:16 +00:00
feat: add independent lowerjaw in labs (#65785)
This commit is contained in:
@@ -518,7 +518,7 @@
|
||||
"ms-link": "Microsoft Link",
|
||||
"submit-and-go": "Submit and go to my next challenge",
|
||||
"congratulations": "Congratulations, your code passes. Submit your code to continue.",
|
||||
"congratulations-code-passes": "✔ Congratulations. Your code passes.",
|
||||
"congratulations-code-passes": "Congratulations. Your code passes.",
|
||||
"i-completed": "I've completed this challenge",
|
||||
"example-code": "Example Code",
|
||||
"test-output": "Your test output will go here",
|
||||
@@ -556,7 +556,7 @@
|
||||
"contact-support-mistake": "If you think there has been a mistake, please contact us at donors@freecodecamp.org",
|
||||
"editor-tabs": {
|
||||
"code": "Code",
|
||||
"tests": "Tests",
|
||||
"tests": "Tests:",
|
||||
"restart": "Restart",
|
||||
"restart-step": "Restart Step",
|
||||
"console": "Console",
|
||||
|
||||
@@ -7,6 +7,7 @@ interface ProgressInnerProps {
|
||||
completedPercent: number;
|
||||
title: string;
|
||||
meta: string;
|
||||
minified?: boolean;
|
||||
}
|
||||
|
||||
const easing = BezierEasing(0.2, 0.5, 0.4, 1);
|
||||
@@ -36,7 +37,8 @@ function useIsInViewport(ref: React.RefObject<HTMLDivElement>) {
|
||||
function ProgressInner({
|
||||
completedPercent,
|
||||
title,
|
||||
meta
|
||||
meta,
|
||||
minified
|
||||
}: ProgressInnerProps): JSX.Element {
|
||||
const [shownPercent, setShownPercent] = useState(0);
|
||||
const [lastShownPercent, setLastShownPercent] = useState(0);
|
||||
@@ -94,6 +96,24 @@ function ProgressInner({
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (minified) {
|
||||
return (
|
||||
<>
|
||||
<div className='progress-header'>
|
||||
<div>{title}</div>
|
||||
<div>{meta}</div>
|
||||
</div>
|
||||
<div
|
||||
className='progress-bar-wrap'
|
||||
aria-hidden='true'
|
||||
ref={progressInnerWrap}
|
||||
>
|
||||
<ProgressBar now={shownPercent} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='completion-block-name'>{title}</div>
|
||||
|
||||
@@ -56,6 +56,7 @@ type PropsFromRedux = ConnectedProps<typeof connector>;
|
||||
|
||||
interface ProgressProps extends PropsFromRedux {
|
||||
t: TFunction;
|
||||
minified?: boolean;
|
||||
}
|
||||
function Progress({
|
||||
currentBlockIds,
|
||||
@@ -65,7 +66,8 @@ function Progress({
|
||||
challengeType,
|
||||
completedChallengesInBlock,
|
||||
completedPercent,
|
||||
t
|
||||
t,
|
||||
minified
|
||||
}: ProgressProps): JSX.Element {
|
||||
useFetchAllCurriculumData(); // needed to compute completedPercent
|
||||
let blockTitle = t(`intro:${superBlock}.blocks.${block}.title`);
|
||||
@@ -103,6 +105,7 @@ function Progress({
|
||||
title={blockTitle}
|
||||
meta={meta}
|
||||
completedPercent={completedPercent}
|
||||
minified={minified}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -315,8 +315,12 @@ function ShowClassic({
|
||||
// AB testing Pre-fetch in the Spanish locale
|
||||
const isPreFetchEnabled = useFeature('prefetch_ab_test').on;
|
||||
|
||||
// Independent lower jaw is only enabled for desktop workshops.
|
||||
const showIndependentLowerJaw = hasEditableBoundaries && !isMobile;
|
||||
// Independent lower jaw is only enabled for desktop.
|
||||
const showIndependentLowerJaw = !isMobile;
|
||||
|
||||
const showSidePanelTests = isMobile || !hasEditableBoundaries;
|
||||
|
||||
// Show test
|
||||
|
||||
useEffect(() => {
|
||||
if (isPreFetchEnabled && envData.clientLocale === 'espanol') {
|
||||
@@ -428,7 +432,7 @@ function ShowClassic({
|
||||
instructionsPanelRef={instructionsPanelRef}
|
||||
toolPanel={toolPanel}
|
||||
hasDemo={hasDemo}
|
||||
showIndependentLowerJaw={showIndependentLowerJaw}
|
||||
showSidePanelTests={showSidePanelTests}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -470,7 +474,7 @@ function ShowClassic({
|
||||
>
|
||||
<LearnLayout>
|
||||
<Helmet title={windowTitle} />
|
||||
{isMobile && (
|
||||
{isMobile ? (
|
||||
<MobileLayout
|
||||
editor={renderEditor({
|
||||
isMobileLayout: true,
|
||||
@@ -502,8 +506,7 @@ function ShowClassic({
|
||||
updateUsingKeyboardInTablist={updateUsingKeyboardInTablist}
|
||||
usesMultifileEditor={usesMultifileEditor}
|
||||
/>
|
||||
)}
|
||||
{!isMobile && (
|
||||
) : (
|
||||
<DesktopLayout
|
||||
challengeFiles={challengeFiles}
|
||||
challengeType={challengeType}
|
||||
@@ -514,7 +517,7 @@ function ShowClassic({
|
||||
hasEditableBoundaries={hasEditableBoundaries}
|
||||
hasPreview={hasPreview}
|
||||
instructions={renderInstructionsPanel({
|
||||
toolPanel: <ToolPanel guideUrl={guideUrl} videoUrl={videoUrl} />,
|
||||
toolPanel: null,
|
||||
hasDemo: demoType === 'onClick'
|
||||
})}
|
||||
isDailyCodingChallenge={isDailyCodingChallenge}
|
||||
@@ -546,6 +549,8 @@ function ShowClassic({
|
||||
challengeTitle={title}
|
||||
challengeBlock={block}
|
||||
superBlock={superBlock}
|
||||
guideUrl={guideUrl}
|
||||
videoUrl={videoUrl}
|
||||
/>
|
||||
<VideoModal videoUrl={videoUrl} />
|
||||
<ResetModal
|
||||
|
||||
@@ -46,6 +46,15 @@
|
||||
.progress-bar-wrap {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
border: 1px solid var(--quaternary-color);
|
||||
}
|
||||
|
||||
.progress-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.progress-bar-background {
|
||||
@@ -57,6 +66,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Button, FormControl, Modal, Spacer } from '@freecodecamp/ui';
|
||||
|
||||
import { t } from 'i18next';
|
||||
import envData from '../../../../config/env.json';
|
||||
import { createQuestion, closeModal } from '../redux/actions';
|
||||
import { createQuestion, closeModal, openModal } from '../redux/actions';
|
||||
import { isHelpModalOpenSelector } from '../redux/selectors';
|
||||
|
||||
import './help-modal.css';
|
||||
@@ -19,6 +19,9 @@ interface HelpModalProps {
|
||||
challengeTitle: string;
|
||||
challengeBlock: string;
|
||||
superBlock: string;
|
||||
guideUrl?: string;
|
||||
videoUrl?: string;
|
||||
openVideoModal: () => void;
|
||||
}
|
||||
|
||||
const { forumLocation } = envData;
|
||||
@@ -31,7 +34,11 @@ const mapStateToProps = (state: unknown) => ({
|
||||
});
|
||||
const mapDispatchToProps = (dispatch: Dispatch) =>
|
||||
bindActionCreators(
|
||||
{ createQuestion, closeHelpModal: () => closeModal('help') },
|
||||
{
|
||||
createQuestion,
|
||||
closeHelpModal: () => closeModal('help'),
|
||||
openVideoModal: () => openModal('video')
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
|
||||
@@ -43,7 +50,6 @@ export const generateSearchLink = (
|
||||
const titleText = t(`intro:${superBlock}.blocks.${block}.title`);
|
||||
const selector = 'in:title';
|
||||
const query = encodeURIComponent(`${titleText} - ${title} ${selector}`);
|
||||
|
||||
const search = `${forumLocation}/search?q=${query}`;
|
||||
return search;
|
||||
};
|
||||
@@ -99,7 +105,10 @@ function HelpModal({
|
||||
isOpen,
|
||||
challengeBlock,
|
||||
superBlock,
|
||||
challengeTitle
|
||||
challengeTitle,
|
||||
guideUrl,
|
||||
videoUrl,
|
||||
openVideoModal
|
||||
}: HelpModalProps): JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
const [showHelpForm, setShowHelpForm] = useState(false);
|
||||
@@ -136,6 +145,11 @@ function HelpModal({
|
||||
resetFormValues();
|
||||
};
|
||||
|
||||
const handleOpenVideo = () => {
|
||||
openVideoModal();
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const handleSubmit = (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -149,13 +163,17 @@ function HelpModal({
|
||||
closeHelpModal();
|
||||
};
|
||||
|
||||
const hintUrl = guideUrl
|
||||
? guideUrl
|
||||
: generateSearchLink(challengeTitle, challengeBlock, superBlock);
|
||||
|
||||
if (isOpen) {
|
||||
callGA({ event: 'pageview', pagePath: '/help-modal' });
|
||||
}
|
||||
return (
|
||||
<Modal onClose={handleClose} open={!!isOpen}>
|
||||
<Modal.Header closeButtonClassNames='close'>
|
||||
{t('buttons.ask-for-help')}
|
||||
{t('buttons.get-help')}
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
{showHelpForm ? (
|
||||
@@ -278,12 +296,38 @@ function HelpModal({
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
block={true}
|
||||
size='large'
|
||||
variant='primary'
|
||||
href={hintUrl}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
data-playwright-test-label='get-hint-modal-button'
|
||||
>
|
||||
{t('buttons.get-hint')}
|
||||
</Button>
|
||||
<Spacer size='xxs' />
|
||||
{videoUrl && (
|
||||
<>
|
||||
<Button
|
||||
block={true}
|
||||
size='large'
|
||||
variant='primary'
|
||||
onClick={handleOpenVideo}
|
||||
data-playwright-test-label='watch-a-video-modal-button'
|
||||
>
|
||||
{t('buttons.watch-video')}
|
||||
</Button>
|
||||
<Spacer size='xxs' />
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
block={true}
|
||||
size='large'
|
||||
variant='primary'
|
||||
onClick={() => setShowHelpForm(true)}
|
||||
data-playwright-test-label='create-post-modal-button'
|
||||
>
|
||||
{t('buttons.create-post')}
|
||||
</Button>
|
||||
@@ -292,7 +336,7 @@ function HelpModal({
|
||||
block={true}
|
||||
size='large'
|
||||
variant='primary'
|
||||
onClick={closeHelpModal}
|
||||
onClick={handleClose}
|
||||
>
|
||||
{t('buttons.cancel')}
|
||||
</Button>
|
||||
|
||||
@@ -8,12 +8,13 @@
|
||||
.independent-lower-jaw .hint-container {
|
||||
background-color: var(--background-quaternary);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
padding: 12px;
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
width: 95%;
|
||||
width: 97%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
margin-bottom: 12px;
|
||||
@@ -22,6 +23,21 @@
|
||||
animation: jaw-hint-fade-in 0.3s ease forwards;
|
||||
}
|
||||
|
||||
.independent-lower-jaw .hint-container .hint-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.independent-lower-jaw .hint-container .hint-header svg {
|
||||
height: 1.4rem;
|
||||
width: 1.4rem;
|
||||
}
|
||||
|
||||
.independent-lower-jaw .hint-container .hint-body p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@keyframes jaw-hint-fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
@@ -57,7 +73,7 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: none;
|
||||
border: 1px solid var(--quaternary-color);
|
||||
}
|
||||
|
||||
.independent-lower-jaw .action-row-right button {
|
||||
@@ -122,6 +138,12 @@
|
||||
|
||||
.share-button-wrapper {
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
justify-content: end;
|
||||
margin-top: 10px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.share-button-wrapper a {
|
||||
border: 1px solid var(--quaternary-color);
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,11 @@ import { createStore } from '../../../redux/create-store';
|
||||
import { mockCurriculumData } from '../utils/__fixtures__/curriculum-data';
|
||||
import { render } from '../../../../utils/test-utils';
|
||||
|
||||
vi.mock('../../../components/Progress');
|
||||
vi.mock('../utils/fetch-all-curriculum-data', () => ({
|
||||
useSubmit: () => vi.fn()
|
||||
}));
|
||||
|
||||
const baseChallengeMeta: ChallengeMeta = {
|
||||
block: 'test-block',
|
||||
id: 'test-challenge-id',
|
||||
@@ -21,12 +26,11 @@ const baseChallengeMeta: ChallengeMeta = {
|
||||
};
|
||||
|
||||
const passingTests: Test[] = [{ pass: true, text: 'test', testString: 'test' }];
|
||||
|
||||
const baseProps = {
|
||||
openHelpModal: vi.fn(),
|
||||
openResetModal: vi.fn(),
|
||||
executeChallenge: vi.fn(),
|
||||
submitChallenge: vi.fn(),
|
||||
saveChallenge: vi.fn(),
|
||||
tests: passingTests,
|
||||
isSignedIn: true,
|
||||
challengeMeta: baseChallengeMeta,
|
||||
|
||||
@@ -2,7 +2,17 @@ import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from '@freecodecamp/ui';
|
||||
import { Button, Spacer } from '@freecodecamp/ui';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
faLightbulb,
|
||||
faClose,
|
||||
faZap,
|
||||
faSave,
|
||||
faClockRotateLeft,
|
||||
faRotateLeft
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import Progress from '../../../components/Progress';
|
||||
import {
|
||||
completedChallengesIdsSelector,
|
||||
isSignedInSelector
|
||||
@@ -16,10 +26,10 @@ import {
|
||||
} from '../redux/selectors';
|
||||
import { apiLocation } from '../../../../config/env.json';
|
||||
import { openModal, executeChallenge } from '../redux/actions';
|
||||
import { saveChallenge } from '../../../redux/actions';
|
||||
import Help from '../../../assets/icons/help';
|
||||
import callGA from '../../../analytics/call-ga';
|
||||
import { Share } from '../../../components/share';
|
||||
import Reset from '../../../assets/icons/reset';
|
||||
import { useSubmit } from '../utils/fetch-all-curriculum-data';
|
||||
|
||||
import './independent-lower-jaw.css';
|
||||
@@ -51,13 +61,15 @@ const mapStateToProps = createSelector(
|
||||
const mapDispatchToProps = {
|
||||
openHelpModal: () => openModal('help'),
|
||||
openResetModal: () => openModal('reset'),
|
||||
executeChallenge
|
||||
executeChallenge,
|
||||
saveChallenge
|
||||
};
|
||||
|
||||
interface IndependentLowerJawProps {
|
||||
openHelpModal: () => void;
|
||||
openResetModal: () => void;
|
||||
executeChallenge: () => void;
|
||||
saveChallenge: () => void;
|
||||
tests: Test[];
|
||||
isSignedIn: boolean;
|
||||
challengeMeta: ChallengeMeta;
|
||||
@@ -69,6 +81,7 @@ export function IndependentLowerJaw({
|
||||
openHelpModal,
|
||||
openResetModal,
|
||||
executeChallenge,
|
||||
saveChallenge,
|
||||
tests,
|
||||
isSignedIn,
|
||||
challengeMeta,
|
||||
@@ -123,6 +136,7 @@ export function IndependentLowerJaw({
|
||||
};
|
||||
|
||||
const isMacOS = navigator.userAgent.includes('Mac OS');
|
||||
const showRevertButton = isSignedIn && challengeMeta.saveSubmissionToDB;
|
||||
const checkButtonText = isMacOS
|
||||
? t('buttons.command-enter')
|
||||
: t('buttons.ctrl-enter');
|
||||
@@ -138,14 +152,19 @@ export function IndependentLowerJaw({
|
||||
className='hint-container'
|
||||
data-playwright-test-label='independentLowerJaw-failing-hint'
|
||||
>
|
||||
<div className='hint-header'>
|
||||
<FontAwesomeIcon icon={faLightbulb} />
|
||||
<button
|
||||
className={'tooltip'}
|
||||
data-playwright-test-label='independentLowerJaw-hint-close-button'
|
||||
onClick={() => setShowHint(false)}
|
||||
aria-label={t('buttons.close')}
|
||||
>
|
||||
<FontAwesomeIcon icon={faClose} />
|
||||
<span className='tooltiptext'> {t('buttons.close')}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div dangerouslySetInnerHTML={{ __html: hint }} />
|
||||
<button
|
||||
className={'tooltip'}
|
||||
data-playwright-test-label='independentLowerJaw-hint-close-button'
|
||||
onClick={() => setShowHint(false)}
|
||||
>
|
||||
×<span className='tooltiptext'> {t('buttons.close')}</span>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{isChallengeComplete && showSubmissionHint && (
|
||||
@@ -153,18 +172,37 @@ export function IndependentLowerJaw({
|
||||
className='hint-container'
|
||||
data-playwright-test-label='independentLowerJaw-submission-hint'
|
||||
>
|
||||
<div>
|
||||
<p>{t('learn.congratulations-code-passes')}</p>
|
||||
{isSignedIn && showShareButton && (
|
||||
<div className='share-button-wrapper'>
|
||||
<Share
|
||||
superBlock={challengeMeta.superBlock}
|
||||
block={challengeMeta.block}
|
||||
minified={true}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!isSignedIn && (
|
||||
<div className='hint-header'>
|
||||
<FontAwesomeIcon icon={faZap} />
|
||||
<button
|
||||
className={'tooltip'}
|
||||
aria-label={t('buttons.close')}
|
||||
data-playwright-test-label='independentLowerJaw-submission-hint-close-button'
|
||||
onClick={() => setShowSubmissionHint(false)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faClose} />
|
||||
<span className='tooltiptext'> {t('buttons.close')}</span>
|
||||
</button>
|
||||
</div>
|
||||
<b>{t('learn.congratulations-code-passes')}</b>
|
||||
<div className='progress-bar-container'>
|
||||
<Progress minified={true} />
|
||||
</div>
|
||||
{isSignedIn && showShareButton && (
|
||||
<div
|
||||
className='share-button-wrapper'
|
||||
data-testid='share-button-wrapper'
|
||||
>
|
||||
<Share
|
||||
superBlock={challengeMeta.superBlock}
|
||||
block={challengeMeta.block}
|
||||
minified={true}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!isSignedIn && (
|
||||
<>
|
||||
<Spacer size='xxs' />
|
||||
<a
|
||||
href={`${apiLocation}/signin`}
|
||||
className='btn-cta btn btn-block'
|
||||
@@ -178,15 +216,8 @@ export function IndependentLowerJaw({
|
||||
>
|
||||
{t('learn.sign-in-save')}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
className={'tooltip'}
|
||||
data-playwright-test-label='independentLowerJaw-submission-hint-close-button'
|
||||
onClick={() => setShowSubmissionHint(false)}
|
||||
>
|
||||
×<span className='tooltiptext'> {t('buttons.close')}</span>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -198,6 +229,7 @@ export function IndependentLowerJaw({
|
||||
className={`${isSignedIn && 'btn-cta'} tooltip`}
|
||||
id='independent-lower-jaw-submit-button'
|
||||
data-playwright-test-label='independentLowerJaw-submit-button'
|
||||
aria-label={t('buttons.submit-continue')}
|
||||
onClick={() => submitChallenge()}
|
||||
ref={submitButtonRef}
|
||||
>
|
||||
@@ -211,6 +243,7 @@ export function IndependentLowerJaw({
|
||||
type='button'
|
||||
className='btn-cta tooltip'
|
||||
data-playwright-test-label='independentLowerJaw-check-button'
|
||||
aria-label={t('buttons.check-code')}
|
||||
onClick={handleCheckButtonClick}
|
||||
>
|
||||
{t('buttons.check-code')}
|
||||
@@ -221,19 +254,46 @@ export function IndependentLowerJaw({
|
||||
)}
|
||||
</div>
|
||||
<div className='action-row-right'>
|
||||
<button
|
||||
type='button'
|
||||
className='icon-botton tooltip'
|
||||
data-playwright-test-label='independentLowerJaw-reset-button'
|
||||
onClick={openResetModal}
|
||||
>
|
||||
<Reset />
|
||||
<span className='tooltiptext'> {t('buttons.reset')}</span>
|
||||
</button>
|
||||
{showRevertButton ? (
|
||||
<>
|
||||
<button
|
||||
type='button'
|
||||
className='icon-botton tooltip'
|
||||
data-playwright-test-label='independentLowerJaw-save-button'
|
||||
aria-label={t('buttons.save')}
|
||||
onClick={() => saveChallenge()}
|
||||
>
|
||||
<FontAwesomeIcon icon={faSave} />
|
||||
<span className='tooltiptext'> {t('buttons.save')}</span>
|
||||
</button>
|
||||
<button
|
||||
type='button'
|
||||
className='icon-botton tooltip'
|
||||
data-playwright-test-label='independentLowerJaw-revert-button'
|
||||
aria-label={t('buttons.revert')}
|
||||
onClick={openResetModal}
|
||||
>
|
||||
<FontAwesomeIcon icon={faClockRotateLeft} />
|
||||
<span className='tooltiptext'> {t('buttons.revert')}</span>
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<button
|
||||
type='button'
|
||||
className='icon-botton tooltip'
|
||||
data-playwright-test-label='independentLowerJaw-reset-button'
|
||||
aria-label={t('buttons.reset')}
|
||||
onClick={openResetModal}
|
||||
>
|
||||
<FontAwesomeIcon icon={faRotateLeft} />
|
||||
<span className='tooltiptext'> {t('buttons.reset')}</span>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type='button'
|
||||
className='icon-botton tooltip'
|
||||
data-playwright-test-label='independentLowerJaw-help-button'
|
||||
aria-label={t('buttons.help')}
|
||||
onClick={openHelpModal}
|
||||
>
|
||||
<Help />
|
||||
|
||||
@@ -34,7 +34,7 @@ interface SidePanelProps extends DispatchProps, StateProps {
|
||||
hasDemo: boolean;
|
||||
toolPanel: ReactNode;
|
||||
tests: Test[];
|
||||
showIndependentLowerJaw: boolean;
|
||||
showSidePanelTests?: boolean;
|
||||
}
|
||||
|
||||
export function SidePanel({
|
||||
@@ -45,7 +45,7 @@ export function SidePanel({
|
||||
toolPanel,
|
||||
tests,
|
||||
openModal,
|
||||
showIndependentLowerJaw
|
||||
showSidePanelTests
|
||||
}: SidePanelProps): JSX.Element {
|
||||
return (
|
||||
<div
|
||||
@@ -72,7 +72,7 @@ export function SidePanel({
|
||||
</p>
|
||||
)}{' '}
|
||||
{challengeDescription}
|
||||
{!showIndependentLowerJaw && (
|
||||
{showSidePanelTests && (
|
||||
<>
|
||||
<Spacer size='m' />
|
||||
{toolPanel}
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
}
|
||||
|
||||
.challenge-test-suite-heading {
|
||||
font-size: 0.9em;
|
||||
text-align: center;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.sk-spinner {
|
||||
@@ -25,6 +24,7 @@
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
line-height: 1.5;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.test-result:nth-child(odd) {
|
||||
@@ -47,11 +47,9 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 60px;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.test-status-icon > svg {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ test('should render the modal content correctly', async ({ page }) => {
|
||||
'/learn/responsive-web-design-v9/workshop-cat-photo-app/step-3'
|
||||
);
|
||||
|
||||
await page.getByTestId('independentLowerJaw-reset-button').click();
|
||||
await page.getByRole('button', { name: translations.buttons.reset }).click();
|
||||
|
||||
await expectToRenderResetModal(page);
|
||||
|
||||
@@ -93,14 +93,12 @@ test('User can reset challenge', async ({ page, isMobile, browserName }) => {
|
||||
// are reset)
|
||||
await page
|
||||
.getByRole('button', {
|
||||
// check-code works on all browsers because it does not include Command
|
||||
// or Ctrl
|
||||
name: translations.buttons['check-code']
|
||||
})
|
||||
.click();
|
||||
|
||||
// Reset the challenge
|
||||
await page.getByTestId('independentLowerJaw-reset-button').click();
|
||||
await page.getByRole('button', { name: translations.buttons.reset }).click();
|
||||
await page
|
||||
.getByRole('button', { name: translations.buttons['reset-lesson'] })
|
||||
.click();
|
||||
@@ -147,11 +145,9 @@ test.describe('When the user is not logged in', () => {
|
||||
await focusEditor({ page, isMobile });
|
||||
await getEditors(page).fill(challengeSolution);
|
||||
|
||||
const submitButton = page.getByRole('button', {
|
||||
name: isMobile
|
||||
? translations.buttons.run
|
||||
: translations.buttons['run-test']
|
||||
});
|
||||
const submitButton = isMobile
|
||||
? page.getByRole('button', { name: translations.buttons.run })
|
||||
: page.getByRole('button', { name: translations.buttons['check-code'] });
|
||||
|
||||
await submitButton.click();
|
||||
|
||||
@@ -161,7 +157,7 @@ test.describe('When the user is not logged in', () => {
|
||||
|
||||
// Completion dialog shows up
|
||||
await expect(
|
||||
page.getByText(translations.buttons['go-to-next'])
|
||||
page.getByText(translations.buttons['submit-continue'])
|
||||
).toBeVisible();
|
||||
|
||||
// Close the dialog
|
||||
@@ -170,11 +166,7 @@ test.describe('When the user is not logged in', () => {
|
||||
.click();
|
||||
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: !isMobile
|
||||
? translations.buttons['reset-lesson']
|
||||
: translations.buttons.reset
|
||||
})
|
||||
.getByRole('button', { name: translations.buttons.reset })
|
||||
.click();
|
||||
|
||||
await page
|
||||
@@ -206,7 +198,7 @@ test('should close when the user clicks the close button', async ({ page }) => {
|
||||
'/learn/responsive-web-design-v9/workshop-cat-photo-app/step-3'
|
||||
);
|
||||
|
||||
await page.getByTestId('independentLowerJaw-reset-button').click();
|
||||
await page.getByRole('button', { name: translations.buttons.reset }).click();
|
||||
|
||||
await expect(
|
||||
page.getByRole('dialog', { name: translations.learn.reset })
|
||||
@@ -242,13 +234,11 @@ 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']
|
||||
})
|
||||
).toBeVisible();
|
||||
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: translations.buttons['revert-to-saved-code']
|
||||
|
||||
@@ -103,11 +103,8 @@ const completeChallenges = async ({
|
||||
challenge.solution
|
||||
);
|
||||
await page.keyboard.press('ControlOrMeta+V');
|
||||
await page.getByRole('button', { name: 'Run' }).click();
|
||||
await expect(
|
||||
page.getByRole('dialog').filter({ hasText: 'Basic Javascript' })
|
||||
).toBeVisible(); // completion dialog
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
await page.getByRole('button', { name: 'Check Your Code' }).click();
|
||||
await page.getByRole('button', { name: 'Submit and continue' }).click();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+88
-7
@@ -1,9 +1,16 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import translations from '../client/i18n/locales/english/translations.json';
|
||||
|
||||
test.describe('help-button tests for a page with three links (hint, help and video)', () => {
|
||||
test.describe('Mobile help-button tests for a page with three links (hint, help and video)', () => {
|
||||
test.use({
|
||||
viewport: { width: 393, height: 851 },
|
||||
isMobile: true
|
||||
});
|
||||
test('should render the button, menu and the three links when video is available', async ({
|
||||
page
|
||||
page,
|
||||
isMobile
|
||||
}) => {
|
||||
test.skip(!isMobile, 'Help dropdown only available on mobile');
|
||||
// visit the page with the video link
|
||||
await page.goto(
|
||||
'/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements'
|
||||
@@ -20,11 +27,17 @@ test.describe('help-button tests for a page with three links (hint, help and vid
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('help-button tests for a page with two links when video is not available', () => {
|
||||
test.describe('Mobile help-button tests for a page with two links when video is not available', () => {
|
||||
test.use({
|
||||
viewport: { width: 393, height: 851 },
|
||||
isMobile: true
|
||||
});
|
||||
test('should render the button, menu and the two links when video is not available', async ({
|
||||
page
|
||||
page,
|
||||
isMobile
|
||||
}) => {
|
||||
// visit the page without the video link
|
||||
test.skip(!isMobile, 'Help dropdown only available on mobile');
|
||||
|
||||
await page.goto(
|
||||
'/learn/front-end-development-libraries/bootstrap/apply-the-default-bootstrap-button-style'
|
||||
);
|
||||
@@ -81,10 +94,78 @@ test.describe('Desktop help-button tests for a page with a reset and help button
|
||||
'learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-3'
|
||||
);
|
||||
await expect(
|
||||
page.getByTestId('independentLowerJaw-reset-button')
|
||||
page.getByRole('button', { name: translations.buttons.reset })
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByTestId('independentLowerJaw-help-button')
|
||||
page.getByRole('button', { name: translations.buttons.help })
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('should open help modal with video button when video is available', async ({
|
||||
page
|
||||
}) => {
|
||||
// visit the page with the video link
|
||||
await page.goto(
|
||||
'/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements'
|
||||
);
|
||||
|
||||
// Click the help button in independent lower jaw
|
||||
const helpButton = page.getByRole('button', {
|
||||
name: translations.buttons.help
|
||||
});
|
||||
await expect(helpButton).toBeVisible();
|
||||
await helpButton.click();
|
||||
|
||||
// Help modal should open
|
||||
await expect(
|
||||
page.getByRole('dialog', { name: translations.buttons['get-help'] })
|
||||
).toBeVisible();
|
||||
|
||||
// Video button should be present in the modal
|
||||
await expect(
|
||||
page.getByRole('button', { name: translations.buttons['watch-video'] })
|
||||
).toBeVisible();
|
||||
|
||||
// Other help options should be present
|
||||
await expect(
|
||||
page.getByRole('link', { name: translations.buttons['get-hint'] })
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole('button', { name: translations.buttons['create-post'] })
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('should open help modal without video button when video is not available', async ({
|
||||
page
|
||||
}) => {
|
||||
// visit the page without the video link
|
||||
await page.goto(
|
||||
'/learn/front-end-development-libraries/bootstrap/apply-the-default-bootstrap-button-style'
|
||||
);
|
||||
|
||||
// Click the help button in independent lower jaw
|
||||
const helpButton = page.getByRole('button', {
|
||||
name: translations.buttons.help
|
||||
});
|
||||
await expect(helpButton).toBeVisible();
|
||||
await helpButton.click();
|
||||
|
||||
// Help modal should open
|
||||
await expect(
|
||||
page.getByRole('dialog', { name: translations.buttons['get-help'] })
|
||||
).toBeVisible();
|
||||
|
||||
// Video button should NOT be present in the modal
|
||||
await expect(
|
||||
page.getByRole('button', { name: translations.buttons['watch-video'] })
|
||||
).toBeHidden();
|
||||
|
||||
// Other help options should be present
|
||||
await expect(
|
||||
page.getByRole('link', { name: translations.buttons['get-hint'] })
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole('button', { name: translations.buttons['create-post'] })
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ test.describe('Help Modal component', () => {
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
page.getByRole('dialog', { name: translations.buttons['ask-for-help'] })
|
||||
page.getByRole('dialog', { name: translations.buttons['get-help'] })
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByText(
|
||||
@@ -52,7 +52,7 @@ test.describe('Help Modal component', () => {
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
page.getByRole('dialog', { name: translations.buttons['ask-for-help'] })
|
||||
page.getByRole('dialog', { name: translations.buttons['get-help'] })
|
||||
).toBeVisible();
|
||||
|
||||
const rsaCheckbox = page.getByRole('checkbox', {
|
||||
@@ -102,7 +102,7 @@ test.describe('Help Modal component', () => {
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
page.getByRole('dialog', { name: translations.buttons['ask-for-help'] })
|
||||
page.getByRole('dialog', { name: translations.buttons['get-help'] })
|
||||
).toBeVisible();
|
||||
|
||||
const rsaCheckbox = page.getByRole('checkbox', {
|
||||
@@ -143,7 +143,7 @@ test.describe('Help Modal component', () => {
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
page.getByRole('dialog', { name: translations.buttons['ask-for-help'] })
|
||||
page.getByRole('dialog', { name: translations.buttons['get-help'] })
|
||||
).toBeVisible();
|
||||
|
||||
const rsaCheckbox = page.getByRole('checkbox', {
|
||||
@@ -189,7 +189,7 @@ test.describe('Help Modal component', () => {
|
||||
.click();
|
||||
|
||||
const dialog = page.getByRole('dialog', {
|
||||
name: translations.buttons['ask-for-help']
|
||||
name: translations.buttons['get-help']
|
||||
});
|
||||
|
||||
await expect(dialog).toBeVisible();
|
||||
@@ -207,7 +207,7 @@ test.describe('Help Modal component', () => {
|
||||
.click();
|
||||
|
||||
const dialog = page.getByRole('dialog', {
|
||||
name: translations.buttons['ask-for-help']
|
||||
name: translations.buttons['get-help']
|
||||
});
|
||||
|
||||
await expect(dialog).toBeVisible();
|
||||
|
||||
@@ -43,7 +43,7 @@ test('Correct Ask for help button', async ({ page }) => {
|
||||
await checkAnswerButton.click();
|
||||
await expect(
|
||||
page.getByRole('heading', {
|
||||
name: translations.buttons['ask-for-help'],
|
||||
name: translations.buttons['get-help'],
|
||||
exact: true
|
||||
})
|
||||
).toBeVisible();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { execSync } from 'child_process';
|
||||
import { test, expect } from '@playwright/test';
|
||||
import translations from '../client/i18n/locales/english/translations.json';
|
||||
import { clearEditor, focusEditor } from './utils/editor';
|
||||
|
||||
test.describe('multifileCertProjects', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
execSync('node ../tools/scripts/seed/seed-demo-user --certified-user');
|
||||
@@ -25,9 +27,7 @@ test.describe('multifileCertProjects', () => {
|
||||
await page.keyboard.type('save1text');
|
||||
await expect(page.getByText('save1text')).toBeVisible();
|
||||
|
||||
await page
|
||||
.getByRole('button', { name: !isMobile ? 'Save your Code' : 'Save' })
|
||||
.click();
|
||||
await page.getByRole('button', { name: translations.buttons.save }).click();
|
||||
|
||||
await expect(page.getByTestId('flash-message')).toContainText(success);
|
||||
|
||||
|
||||
+8
-2
@@ -55,7 +55,11 @@ const runChallengeTest = async (page: Page, isMobile: boolean) => {
|
||||
await page.getByRole('tab', { name: 'Console' }).click();
|
||||
await page.getByText('Run').click();
|
||||
} else {
|
||||
await page.getByText('Run the Tests (Ctrl + Enter)').click();
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: translations.buttons['check-code']
|
||||
})
|
||||
.click();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -95,7 +99,9 @@ test.describe('For classic challenges', () => {
|
||||
text: '<h1>Hello World</h1>'
|
||||
});
|
||||
await runChallengeTest(page, isMobile);
|
||||
await closeButton.click();
|
||||
if (isMobile) {
|
||||
await closeButton.click();
|
||||
}
|
||||
|
||||
await expect(
|
||||
page.getByRole('region', {
|
||||
|
||||
+21
-14
@@ -1,11 +1,8 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import translations from '../client/i18n/locales/english/translations.json';
|
||||
import { clearEditor, focusEditor } from './utils/editor';
|
||||
|
||||
test.describe('Progress bar component in editor', () => {
|
||||
// progress bar shows up for the defeult lower jaw that is only displayed on mobile.
|
||||
test.use({
|
||||
viewport: { width: 390, height: 844 }
|
||||
});
|
||||
test('Should appear with the correct content after the user has submitted their code', async ({
|
||||
page,
|
||||
isMobile,
|
||||
@@ -24,20 +21,24 @@ test.describe('Progress bar component in editor', () => {
|
||||
'<html><body><h1>CatPhotoApp</h1><h2>Cat Photos</h2><p>Everyone loves cute cats online!</p></body></html>'
|
||||
);
|
||||
|
||||
await page.getByRole('button', { name: 'Check Your Code' }).click();
|
||||
await page
|
||||
.getByRole('button', { name: translations.buttons['check-code'] })
|
||||
.click();
|
||||
|
||||
const progressBarContainer = page.getByTestId('progress-bar-container');
|
||||
await expect(progressBarContainer).toContainText(
|
||||
'Learn HTML by Building a Cat Photo App'
|
||||
);
|
||||
await expect(progressBarContainer).toContainText(/\d% complete/);
|
||||
await page
|
||||
.getByRole('button', { name: 'Submit and go to next challenge' })
|
||||
.click();
|
||||
await page.getByRole('button', { name: 'Submit and continue' }).click();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Progress bar component in modal', () => {
|
||||
test.use({
|
||||
viewport: { width: 393, height: 851 },
|
||||
isMobile: true
|
||||
});
|
||||
test('should appear in the completion modal after user has submitted their code', async ({
|
||||
page,
|
||||
isMobile,
|
||||
@@ -51,12 +52,18 @@ test.describe('Progress bar component in modal', () => {
|
||||
|
||||
await page.keyboard.insertText('var myName;');
|
||||
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'Run',
|
||||
exact: false
|
||||
})
|
||||
.click();
|
||||
if (isMobile) {
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'Run',
|
||||
exact: false
|
||||
})
|
||||
.click();
|
||||
} else {
|
||||
await page
|
||||
.getByRole('button', { name: translations.buttons['check-code'] })
|
||||
.click();
|
||||
}
|
||||
|
||||
await expect(page.locator('.completion-block-meta')).toContainText(
|
||||
/\d% complete/
|
||||
|
||||
@@ -158,10 +158,15 @@ test.describe('JavaScript projects can be submitted and then viewed in /settings
|
||||
|
||||
await pasteContent(page);
|
||||
|
||||
await page.getByRole('button', { name: 'Run' }).click();
|
||||
await page
|
||||
.getByRole('button', { name: translations.buttons['check-code'] })
|
||||
.click();
|
||||
|
||||
await page
|
||||
.getByRole('button', { name: 'Go to next challenge', exact: false })
|
||||
.getByRole('button', {
|
||||
name: translations.buttons['submit-continue'],
|
||||
exact: false
|
||||
})
|
||||
.click();
|
||||
|
||||
// Submit the rest with the API.
|
||||
|
||||
@@ -9,10 +9,8 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test.describe('Challenge Side Panel Component', () => {
|
||||
test('should render correctly', async ({ page, isMobile }) => {
|
||||
const toolPanelItem = page.getByText(translations.buttons['get-help']);
|
||||
if (isMobile) {
|
||||
await expect(toolPanelItem).not.toBeVisible();
|
||||
} else {
|
||||
const toolPanelItem = page.getByText(translations.buttons['get-help']);
|
||||
await expect(toolPanelItem).toBeVisible();
|
||||
}
|
||||
await expect(page.getByTestId('challenge-title')).toBeVisible();
|
||||
|
||||
@@ -5,7 +5,9 @@ const runChallengeTest = async (page: Page, isMobile: boolean) => {
|
||||
if (isMobile) {
|
||||
await page.getByText('Run').click();
|
||||
} else {
|
||||
await page.getByText('Run the Tests (Ctrl + Enter)').click();
|
||||
await page
|
||||
.getByRole('button', { name: translations.buttons['check-code'] })
|
||||
.click();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+14
-9
@@ -11,19 +11,22 @@ test.describe('Tool Panel', () => {
|
||||
page,
|
||||
isMobile
|
||||
}) => {
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'Run',
|
||||
exact: false
|
||||
})
|
||||
.click();
|
||||
|
||||
if (isMobile) {
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'Run',
|
||||
exact: false
|
||||
})
|
||||
.click();
|
||||
await page
|
||||
.getByRole('tab', {
|
||||
name: 'Console'
|
||||
})
|
||||
.click();
|
||||
} else {
|
||||
await page
|
||||
.getByRole('button', { name: translations.buttons['check-code'] })
|
||||
.click();
|
||||
}
|
||||
|
||||
await expect(page.getByTestId('output-text')).toContainText(
|
||||
@@ -41,7 +44,7 @@ test.describe('Tool Panel', () => {
|
||||
.click();
|
||||
} else {
|
||||
await page
|
||||
.getByRole('button', { name: translations.buttons['reset-lesson'] })
|
||||
.getByRole('button', { name: translations.buttons.reset })
|
||||
.click();
|
||||
}
|
||||
await expect(
|
||||
@@ -50,8 +53,10 @@ test.describe('Tool Panel', () => {
|
||||
});
|
||||
|
||||
test('should display list with expected links after clicking "Get Help"', async ({
|
||||
page
|
||||
page,
|
||||
isMobile
|
||||
}) => {
|
||||
test.skip(!isMobile, 'Help dropdown only available on mobile');
|
||||
const expectedHelpLinks = [
|
||||
`${translations.buttons['get-hint']} , ${translations.aria['opens-new-window']}`,
|
||||
translations.buttons['watch-video'],
|
||||
|
||||
+56
-6
@@ -4,13 +4,18 @@ import translations from '../client/i18n/locales/english/translations.json';
|
||||
const currentUrlPath =
|
||||
'/learn/responsive-web-design/responsive-web-design-principles/create-a-media-query';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto(currentUrlPath);
|
||||
await page.getByTestId('get-help-dropdown').click();
|
||||
await page.getByTestId('watch-a-video').click();
|
||||
});
|
||||
test.describe('Exit Video Modal E2E Test Suite - Mobile', () => {
|
||||
test.use({
|
||||
viewport: { width: 393, height: 851 },
|
||||
isMobile: true
|
||||
});
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto(currentUrlPath);
|
||||
await page.getByTestId('get-help-dropdown').click();
|
||||
await page.getByTestId('watch-a-video').click();
|
||||
});
|
||||
|
||||
test.describe('Exit Video Modal E2E Test Suite', () => {
|
||||
test('Verifies the Correct Rendering of the Video Modal', async ({
|
||||
page
|
||||
}) => {
|
||||
@@ -44,3 +49,48 @@ test.describe('Exit Video Modal E2E Test Suite', () => {
|
||||
await expect(dialog).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Exit Video Modal E2E Test Suite - Desktop', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto(currentUrlPath);
|
||||
// Open help modal via independent lower jaw
|
||||
await page.getByRole('button', { name: translations.buttons.help }).click();
|
||||
// Click watch video link from help modal
|
||||
await page.getByTestId('watch-a-video-modal-button').click();
|
||||
});
|
||||
|
||||
test('Verifies the Correct Rendering of the Video Modal on Desktop', async ({
|
||||
page
|
||||
}) => {
|
||||
const dialog = page.getByRole('dialog', {
|
||||
name: translations.buttons['watch-video']
|
||||
});
|
||||
|
||||
await expect(dialog).toBeVisible();
|
||||
await expect(
|
||||
page.getByTestId('video-modal-video-player-iframe')
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByText(translations.learn['scrimba-tip'])
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
dialog.getByRole('button', { name: translations.buttons.close })
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('Closes the Video Modal When the User clicks on exit button on Desktop', async ({
|
||||
page
|
||||
}) => {
|
||||
const dialog = page.getByRole('dialog', {
|
||||
name: translations.buttons['watch-video']
|
||||
});
|
||||
|
||||
await expect(dialog).toBeVisible();
|
||||
|
||||
await dialog
|
||||
.getByRole('button', { name: translations.buttons.close })
|
||||
.click();
|
||||
|
||||
await expect(dialog).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user