feat(client): add gp instructions for rdb (#53612)

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>
This commit is contained in:
Tom
2024-02-12 10:26:33 -06:00
committed by GitHub
parent 7d18cae643
commit 72a96eebcf
29 changed files with 157 additions and 223 deletions
+1 -1
View File
@@ -1449,7 +1449,7 @@
"legacy-go-back": "Go to the current version of the curriculum.",
"course-maintenance": "These courses are undergoing maintenance. If they are not working, you can learn how to run them locally at <0>https://www.freecodecamp.org/news/how-to-run-freecodecamps-relational-databases-curriculum-using-docker-vscode-and-coderoad</0>.",
"course-disabling-soon": "The browser version of these courses will be temporarily disabled soon and your virtual machines will be deleted. Any progress in your virtual machines will be lost. If you have any files you want from them, you should save them to your computer. We apologize for any inconvenience. We hope to have an improved browser version of these courses available again in the next few weeks.",
"course-disabled": "These courses are temporarily unavailable to run in the browser. We apologize for any inconvenience. You can learn how to run them locally at <0>https://www.freecodecamp.org/news/how-to-run-freecodecamps-relational-databases-curriculum-using-docker-vscode-and-coderoad</0>. We hope to have an improved browser version available again in the next few weeks.",
"course-disabled": "These courses are temporarily unavailable to run in the browser. We apologize for any inconvenience. You can learn how to run them locally at <0>https://www.freecodecamp.org/news/how-to-run-freecodecamps-relational-databases-curriculum-using-docker-vscode-and-coderoad</0>. We hope to have an improved browser version available again soon.",
"run-locally": "For now, we recommend running the courses locally on your computer. You can learn how at <0>https://www.freecodecamp.org/news/how-to-run-freecodecamps-relational-databases-curriculum-using-docker-vscode-and-coderoad</0>.",
"progress-wont-save": "Your progress will not be saved to your freeCodeCamp account when running them locally.",
"go-back-to-learn": "Go back to the stable version of the curriculum.",
@@ -416,6 +416,21 @@
"help-translate-link": "Help us translate.",
"project-preview-title": "Here's a preview of what you will build",
"github-required": "<0>Create a GitHub</0> account if you don't have one. You'll need it when you create the virtual Linux server machine. This process may take a few minutes.",
"gitpod": {
"intro": "This course runs in a virtual Linux machine using Gitpod. Follow these instructions to start the course:",
"step-1": "<0>Create a GitHub</0> account if you don't have one",
"step-2": "Click the start button below",
"step-3": "Login to Gitpod with your GitHub account if you aren't already",
"step-4": "Once the virtual Linux machine is finished loading, start the CodeRoad extension by:",
"step-5": "Clicking the \"hamburger\" menu near the top left of the VSCode window,",
"step-6": "Going to the \"View\" menu,",
"step-7": "Clicking on the \"Command Palette\" option,",
"step-8": "and running the \"CodeRoad: Start\" command",
"step-9": "Follow the instructions in CodeRoad to complete the course",
"continue-project": "Clicking the button below will start a new project. If you have previously started the {{course}} course, go to <0>your Gitpod dashboard</0> to continue.",
"learn-more": "Learn more about <0>Gitpod workspaces.</0>",
"logout-warning": "If you log out of freeCodeCamp before you complete the entire {{course}} course, your progress will not be saved to your freeCodeCamp account."
},
"step-1": "Step 1: Complete the project",
"step-2": "Step 2: Submit your code",
"submit-public-url": "When you have completed the project, save all the required files into a public repository and submit the URL to it below.",
@@ -1,25 +1,29 @@
import { faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React from 'react';
import { useFeature } from '@growthbook/growthbook-react';
import { useTranslation } from 'react-i18next';
import { Button } from '@freecodecamp/ui';
interface CodeAllyButtonProps {
onClick: () => void;
text: string;
onClick: () => void;
}
export function CodeAllyButton(props: CodeAllyButtonProps): JSX.Element | null {
const codeAllyDisabledFeature = useFeature('codeally_disabled');
const { t } = useTranslation();
return (
<Button
aria-describedby='codeally-cookie-warning'
block={true}
variant='primary'
data-cy='start-codeally'
onClick={codeAllyDisabledFeature.on ? () => {} : props.onClick}
disabled={codeAllyDisabledFeature.on}
onClick={props.onClick}
variant='primary'
block={true}
>
{props.text}
<span className='sr-only'>, {t('aria.opens-new-window')}</span>
{props.text}&nbsp;&nbsp;
<FontAwesomeIcon icon={faExternalLinkAlt} />
</Button>
);
}
@@ -25,29 +25,6 @@ const Down = () => {
);
};
const DisablingSoon = () => {
const { t } = useTranslation();
return (
<Alert variant='danger'>
<p>{t('intro:misc-text.course-disabling-soon')}</p>
<Spacer size='small' />
<p>
<Trans i18nKey='intro:misc-text.run-locally'>
<a
href='https://www.freecodecamp.org/news/how-to-run-freecodecamps-relational-databases-curriculum-using-docker-vscode-and-coderoad'
rel='noreferrer'
target='_blank'
>
placeholder
</a>
</Trans>
</p>
<Spacer size='small' />
<p>{t('intro:misc-text.progress-wont-save')}</p>
</Alert>
);
};
const Disabled = () => {
const { t } = useTranslation();
return (
@@ -71,13 +48,10 @@ const Disabled = () => {
export function CodeAllyDown(): JSX.Element | null {
const codeAllyDownFeature = useFeature('codeally_down');
const codeAllyDisablingSoonFeature = useFeature('codeally_disabling_soon');
const codeAllyDisabledFeature = useFeature('codeally_disabled');
return codeAllyDisabledFeature.on ? (
<Disabled />
) : codeAllyDisablingSoonFeature.on ? (
<DisablingSoon />
) : codeAllyDownFeature.on ? (
<Down />
) : null;
@@ -1,21 +0,0 @@
import React from 'react';
import { useFeature } from '@growthbook/growthbook-react';
interface CodeAllyIframeProps {
src: string;
}
export function CodeAllyIframe(props: CodeAllyIframeProps): JSX.Element | null {
const codeAllyDisabledFeature = useFeature('codeally_disabled');
return codeAllyDisabledFeature.on ? null : (
<iframe
className='codeally-frame'
data-cy='codeally-frame'
name={`codeAlly${Date.now()}`}
sandbox='allow-modals allow-forms allow-popups allow-scripts allow-same-origin'
src={props.src}
title='Editor'
/>
);
}
+1 -7
View File
@@ -26,7 +26,6 @@ import {
userSelector,
isOnlineSelector,
isServerOnlineSelector,
showCodeAllySelector,
userFetchStateSelector
} from '../../redux/selectors';
@@ -60,7 +59,6 @@ const mapStateToProps = createSelector(
isOnlineSelector,
isServerOnlineSelector,
userFetchStateSelector,
showCodeAllySelector,
userSelector,
(
isSignedIn,
@@ -69,7 +67,6 @@ const mapStateToProps = createSelector(
isOnline: boolean,
isServerOnline: boolean,
fetchState: UserFetchState,
showCodeAlly: boolean,
user: User
) => ({
isSignedIn,
@@ -80,7 +77,6 @@ const mapStateToProps = createSelector(
isServerOnline,
fetchState,
theme: user.theme,
showCodeAlly,
user
})
);
@@ -108,7 +104,6 @@ interface DefaultLayoutProps extends StateProps, DispatchProps {
isChallenge?: boolean;
block?: string;
examInProgress: boolean;
showCodeAlly: boolean;
superBlock?: string;
}
@@ -134,7 +129,6 @@ function DefaultLayout({
block,
superBlock,
theme,
showCodeAlly,
user,
fetchUser,
updateAllChallengesInfo
@@ -248,7 +242,7 @@ function DefaultLayout({
/>
) : null}
<SignoutModal />
{isChallenge && !showCodeAlly && !examInProgress && (
{isChallenge && !examInProgress && (
<div className='breadcrumbs-demo'>
<BreadCrumb
block={block as string}
-7
View File
@@ -31,13 +31,6 @@ body {
min-height: 80vh;
}
.codeally-frame {
display: block;
height: calc(100vh - var(--header-height));
width: 100%;
border: 0;
}
.btn-cta-big {
max-height: 100%;
font-size: 1.5rem;
-3
View File
@@ -8,7 +8,6 @@ export const actionTypes = createTypes(
'hardGoTo',
'allowBlockDonationRequests',
'setRenderStartTime',
'hideCodeAlly',
'preventBlockDonationRequests',
'setCompletionCountWhenShownProgressModal',
'setShowMultipleProgressModals',
@@ -19,10 +18,8 @@ export const actionTypes = createTypes(
'onlineStatusChange',
'serverStatusChange',
'resetUserData',
'tryToShowCodeAlly',
'tryToShowDonationModal',
'executeGA',
'showCodeAlly',
'startExam',
'stopExam',
'clearExamResults',
-4
View File
@@ -101,10 +101,6 @@ export const deleteUserTokenComplete = createAction(
actionTypes.deleteUserTokenComplete
);
export const hideCodeAlly = createAction(actionTypes.hideCodeAlly);
export const showCodeAlly = createAction(actionTypes.showCodeAlly);
export const tryToShowCodeAlly = createAction(actionTypes.tryToShowCodeAlly);
export const startExam = createAction(actionTypes.startExam);
export const stopExam = createAction(actionTypes.stopExam);
export const clearExamResults = createAction(actionTypes.clearExamResults);
-38
View File
@@ -1,38 +0,0 @@
import { call, put, select, takeEvery } from 'redux-saga/effects';
import { createFlashMessage } from '../components/Flash/redux';
import { FlashMessages } from '../components/Flash/redux/flash-messages';
import { postUserToken } from '../utils/ajax';
import { showCodeAlly, updateUserToken } from './actions';
import { isSignedInSelector, userTokenSelector } from './selectors';
const startProjectErrMessage = {
type: 'danger',
message: FlashMessages.StartProjectErr
};
function* tryToShowCodeAllySaga() {
const isSignedIn = yield select(isSignedInSelector);
const hasUserToken = !!(yield select(userTokenSelector));
if (!isSignedIn || hasUserToken) {
yield put(showCodeAlly());
} else {
try {
const { data } = yield call(postUserToken);
if (data?.userToken) {
yield put(updateUserToken(data.userToken));
yield put(showCodeAlly());
} else {
yield put(createFlashMessage(startProjectErrMessage));
}
} catch (e) {
yield put(createFlashMessage(startProjectErrMessage));
}
}
}
export function createCodeAllySaga(types) {
return [takeEvery(types.tryToShowCodeAlly, tryToShowCodeAllySaga)];
}
-15
View File
@@ -9,7 +9,6 @@ import {
import { createAcceptTermsSaga } from './accept-terms-saga';
import { actionTypes, ns as MainApp } from './action-types';
import { createAppMountSaga } from './app-mount-saga';
import { createCodeAllySaga } from './codeally-saga';
import { createDonationSaga } from './donation-saga';
import failedUpdatesEpic from './failed-updates-epic';
import { createFetchUserSaga } from './fetch-user-saga';
@@ -63,7 +62,6 @@ const initialState = {
showCertFetchState: {
...defaultFetchState
},
showCodeAlly: false,
user: {},
userFetchState: {
...defaultFetchState
@@ -93,7 +91,6 @@ export const epics = [hardGoToEpic, failedUpdatesEpic, updateCompleteEpic];
export const sagas = [
...createAcceptTermsSaga(actionTypes),
...createAppMountSaga(actionTypes),
...createCodeAllySaga(actionTypes),
...createDonationSaga(actionTypes),
...createGaSaga(actionTypes),
...createFetchUserSaga(actionTypes),
@@ -418,18 +415,6 @@ export const reducer = handleActions(
}
};
},
[actionTypes.hideCodeAlly]: state => {
return {
...state,
showCodeAlly: false
};
},
[actionTypes.showCodeAlly]: state => {
return {
...state,
showCodeAlly: true
};
},
[actionTypes.startExam]: state => {
return {
...state,
-4
View File
@@ -78,10 +78,6 @@ export const userTokenSelector = state => {
return userSelector(state).userToken;
};
export const showCodeAllySelector = state => {
return state[MainApp].showCodeAlly;
};
export const examInProgressSelector = state => {
return state[MainApp].examInProgress;
};
+114 -59
View File
@@ -20,11 +20,10 @@ import { challengeTypes } from '../../../../../shared/config/challenge-types';
import CompletionModal from '../components/completion-modal';
import HelpModal from '../components/help-modal';
import Hotkeys from '../components/hotkeys';
import { hideCodeAlly, tryToShowCodeAlly } from '../../../redux/actions';
import { updateUserToken } from '../../../redux/actions';
import {
completedChallengesSelector,
partiallyCompletedChallengesSelector,
showCodeAllySelector,
isSignedInSelector,
userTokenSelector
} from '../../../redux/selectors';
@@ -46,9 +45,9 @@ import SolutionForm from '../projects/solution-form';
import { FlashMessages } from '../../../components/Flash/redux/flash-messages';
import { SuperBlocks } from '../../../../../shared/config/superblocks';
import { CodeAllyDown } from '../../../components/growth-book/codeally-down';
import { postUserToken } from '../../../utils/ajax';
import './codeally.css';
import { CodeAllyIframe } from '../../../components/growth-book/codeally-iframe';
import { CodeAllyButton } from '../../../components/growth-book/codeally-button';
// Redux
@@ -57,21 +56,18 @@ const mapStateToProps = createSelector(
isChallengeCompletedSelector,
isSignedInSelector,
partiallyCompletedChallengesSelector,
showCodeAllySelector,
userTokenSelector,
(
completedChallenges: CompletedChallenge[],
isChallengeCompleted: boolean,
isSignedIn: boolean,
partiallyCompletedChallenges: CompletedChallenge[],
showCodeAlly: boolean,
userToken: string | null
) => ({
completedChallenges,
isChallengeCompleted,
isSignedIn,
partiallyCompletedChallenges,
showCodeAlly,
userToken
})
);
@@ -81,9 +77,8 @@ const mapDispatchToProps = (dispatch: Dispatch) =>
{
challengeMounted,
createFlashMessage,
hideCodeAlly,
openCompletionModal: () => openModal('completion'),
tryToShowCodeAlly,
updateUserToken,
updateChallengeMeta,
updateSolutionFormValues
},
@@ -96,7 +91,6 @@ interface ShowCodeAllyProps {
completedChallenges: CompletedChallenge[];
createFlashMessage: typeof createFlashMessage;
data: { challengeNode: ChallengeNode };
hideCodeAlly: () => void;
isChallengeCompleted: boolean;
isSignedIn: boolean;
openCompletionModal: () => void;
@@ -104,10 +98,9 @@ interface ShowCodeAllyProps {
challengeMeta: ChallengeMeta;
};
partiallyCompletedChallenges: CompletedChallenge[];
showCodeAlly: boolean;
t: TFunction;
tryToShowCodeAlly: () => void;
updateChallengeMeta: (arg0: ChallengeMeta) => void;
updateUserToken: (arg0: string) => void;
updateSolutionFormValues: () => void;
userToken: string | null;
}
@@ -137,10 +130,6 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
this.container.current?.focus();
}
componentWillUnmount() {
this.props.hideCodeAlly();
}
handleSubmit = ({
showCompletionModal
}: {
@@ -176,6 +165,49 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
}
};
openGitpod = (userToken?: string) => {
const {
data: {
challengeNode: {
challenge: { url }
}
}
} = this.props;
const repoUrl = `https://github.com/${url}`;
const coderoadTutorial = encodeURIComponent(
`https://raw.githubusercontent.com/${url}/main/tutorial.json`
);
const gitpodDomain = `https://gitpod.io/?autostart=true#CODEROAD_TUTORIAL_URL=${coderoadTutorial},CODEROAD_DISABLE_RUN_ON_SAVE=true`;
const tokenEnv = userToken ? `,CODEROAD_WEBHOOK_TOKEN=${userToken}` : '';
const gitpodUrl = `${gitpodDomain}${tokenEnv}/${repoUrl}`;
window.open(gitpodUrl, '_blank');
};
startCourse = async () => {
const { isSignedIn, userToken, updateUserToken } = this.props;
if (!isSignedIn) {
this.openGitpod();
} else if (!userToken) {
const createUserTokenResponse = await postUserToken();
const { data = { userToken: null } } = createUserTokenResponse;
if (data?.userToken) {
updateUserToken(data.userToken);
this.openGitpod(data.userToken);
} else {
createFlashMessage({
type: 'danger',
message: FlashMessages.StartProjectErr
});
}
} else {
this.openGitpod(userToken);
}
};
render() {
const {
completedChallenges,
@@ -190,8 +222,7 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
notes,
superBlock,
title,
translationPending,
url
translationPending
}
}
},
@@ -201,11 +232,8 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
challengeMeta: { nextChallengePath, prevChallengePath }
},
partiallyCompletedChallenges,
showCodeAlly,
t,
tryToShowCodeAlly,
updateSolutionFormValues,
userToken = null
updateSolutionFormValues
} = this.props;
const blockNameTitle = `${t(
@@ -213,22 +241,6 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
)}: ${title}`;
const windowTitle = `${blockNameTitle} | freeCodeCamp.org`;
// Initial CodeAlly login includes a tempToken in redirect URL
const queryParams = new URLSearchParams(window.location.search);
const codeAllyTempToken: string | null = queryParams.get('tempToken');
const tempToken = codeAllyTempToken ? `tempToken=${codeAllyTempToken}` : '';
// Include a unique param to avoid CodeAlly caching issues
const date = `date=${Date.now()}`;
// User token for submitting CodeRoad tutorials
const envVariables = userToken
? `envVariables=CODEROAD_WEBHOOK_TOKEN=${userToken}`
: '';
const goBackTo = `goBackTo=${window.location.href}`;
const isPartiallyCompleted = partiallyCompletedChallenges.some(
challenge => challenge.id === challengeId
);
@@ -236,15 +248,8 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
const isCompleted = completedChallenges.some(
challenge => challenge.id === challengeId
);
const titleContext = t('learn.source-code-link');
return showCodeAlly ? (
<LearnLayout>
<Helmet title={windowTitle} />
<CodeAllyIframe
src={`https://codeally.io/embed/?repoUrl=${url}&${goBackTo}&${envVariables}&${tempToken}&${date}`}
/>
</LearnLayout>
) : (
return (
<Hotkeys
containerRef={this.container}
nextChallengePath={nextChallengePath}
@@ -268,17 +273,38 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
<PrismFormatted text={description} />
<Spacer size='medium' />
<div className='ca-description'>
<Trans i18nKey='learn.github-required'>
<a
href='https://github.com/join'
rel='noopener noreferrer'
target='_blank'
title={titleContext}
>
placeholder
</a>
</Trans>
<p>{t('learn.gitpod.intro')}</p>
<ol>
<li>
<Trans i18nKey='learn.gitpod.step-1'>
<a
href='https://github.com/join'
rel='noopener noreferrer'
target='_blank'
title={t('learn.source-code-link')}
>
placeholder
</a>
</Trans>
</li>
<li>{t('learn.gitpod.step-2')}</li>
<li>{t('learn.gitpod.step-3')}</li>
<li>
{t('learn.gitpod.step-4')}
<ul>
<li>{t('learn.gitpod.step-5')}</li>
<li>{t('learn.gitpod.step-6')}</li>
<li>{t('learn.gitpod.step-7')}</li>
<li>{t('learn.gitpod.step-8')}</li>
</ul>
</li>
<li>{t('learn.gitpod.step-9')}</li>
</ol>
</div>
<Spacer size='medium' />
{isSignedIn &&
challengeType === challengeTypes.codeAllyCert && (
@@ -301,16 +327,45 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
<Spacer size='medium' />
</>
)}
<Alert id='codeally-cookie-warning' variant='info'>
<p>{t(`intro:misc-text.enable-cookies`)}</p>
<Alert variant='info'>
<p>
<Trans
values={{ course: title }}
i18nKey='learn.gitpod.continue-project'
>
<a
href='https://gitpod.io/workspaces'
rel='noopener noreferrer'
target='_blank'
>
placeholder
</a>
</Trans>
</p>
<Trans i18nKey='learn.gitpod.learn-more'>
<a
href='https://forum.freecodecamp.org/t/using-gitpod-in-the-curriculum/668669'
rel='noopener noreferrer'
target='_blank'
>
placeholder
</a>
</Trans>
</Alert>
{isSignedIn && (
<Alert variant='danger'>
{t('learn.gitpod.logout-warning', { course: title })}
</Alert>
)}
<CodeAllyButton
onClick={tryToShowCodeAlly}
text={
challengeType === challengeTypes.codeAllyCert
? t('buttons.click-start-project')
: t('buttons.click-start-course')
}
// `this.startCourse` being an async callback is acceptable
//eslint-disable-next-line @typescript-eslint/no-misused-promises
onClick={this.startCourse}
/>
{isSignedIn &&
challengeType === challengeTypes.codeAllyCert && (
@@ -1,7 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Alert } from '@freecodecamp/ui';
import { useFeature } from '@growthbook/growthbook-react';
import { SuperBlocks } from '../../../../../shared/config/superblocks';
import { isOldRespCert, isRelationalDbCert } from '../../../utils/is-a-cert';
import { Link } from '../../../components/helpers';
@@ -18,7 +17,6 @@ interface LegacyLinksProps {
function LegacyLinks({ superBlock }: LegacyLinksProps): JSX.Element {
const { t } = useTranslation();
const codeAllyDisabledFeature = useFeature('codeally_disabled');
if (isOldRespCert(superBlock)) {
return (
@@ -42,19 +40,6 @@ function LegacyLinks({ superBlock }: LegacyLinksProps): JSX.Element {
<p>{t('intro:misc-text.english-only')}</p>
</Alert>
)}
{codeAllyDisabledFeature.on ? null : (
<Alert variant='info'>
<p>
<Link
external={true}
sameTab={false}
to={`https://forum.freecodecamp.org/t/how-to-troubleshoot-the-web-version-of-the-relational-database-curriculum/500231`}
>
{t('intro:misc-text.read-database-cert-article')}
</Link>
</p>
</Alert>
)}
</>
);
} else {
@@ -3,7 +3,7 @@ id: 5f1a4ef5d5d6b5ab580fc6ae
title: Build a Celestial Bodies Database
challengeType: 13
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-celestial-bodies-database
url: freeCodeCamp/learn-celestial-bodies-database
dashedName: build-a-celestial-bodies-database
---
@@ -3,7 +3,7 @@ id: 602da04c22201c65d2a019f4
title: Build a Number Guessing Game
challengeType: 13
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-number-guessing-game
url: freeCodeCamp/learn-number-guessing-game
dashedName: build-a-number-guessing-game
---
@@ -3,7 +3,7 @@ id: 602d9ff222201c65d2a019f2
title: Build a Periodic Table Database
challengeType: 13
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-periodic-table-database
url: freeCodeCamp/learn-periodic-table-database
dashedName: build-a-periodic-table-database
---
@@ -3,7 +3,7 @@ id: 5f87ac112ae598023a42df1a
title: Build a Salon Appointment Scheduler
challengeType: 13
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-salon-appointment-scheduler
url: freeCodeCamp/learn-salon-appointment-scheduler
dashedName: build-a-salon-appointment-scheduler
---
@@ -3,7 +3,7 @@ id: 5f9771307d4d22b9d2b75a94
title: Build a World Cup Database
challengeType: 13
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-world-cup-database
url: freeCodeCamp/learn-world-cup-database
dashedName: build-a-world-cup-database
---
@@ -3,7 +3,7 @@ id: 602da0de22201c65d2a019f6
title: Build a Kitty Ipsum Translator
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-advanced-bash-by-building-a-kitty-ipsum-translator
url: freeCodeCamp/learn-advanced-bash-by-building-a-kitty-ipsum-translator
dashedName: build-a-kitty-ipsum-translator
---
@@ -3,7 +3,7 @@ id: 5f5b969a05380d2179fe6e18
title: Build a Bike Rental Shop
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-bash-and-sql-by-building-a-bike-rental-shop
url: freeCodeCamp/learn-bash-and-sql-by-building-a-bike-rental-shop
dashedName: build-a-bike-rental-shop
---
@@ -3,7 +3,7 @@ id: 5ea8adfab628f68d805bfc5e
title: Build a Boilerplate
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-bash-by-building-a-boilerplate
url: freeCodeCamp/learn-bash-by-building-a-boilerplate
dashedName: build-a-boilerplate
---
@@ -3,7 +3,7 @@ id: 5f5904ac738bc2fa9efecf5a
title: Build Five Programs
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-bash-scripting-by-building-five-programs
url: freeCodeCamp/learn-bash-scripting-by-building-five-programs
dashedName: build-five-programs
---
@@ -3,7 +3,7 @@ id: 5fa323cdaf6a73463d590659
title: Build an SQL Reference Object
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-git-by-building-an-sql-reference-object
url: freeCodeCamp/learn-git-by-building-an-sql-reference-object
dashedName: build-an-sql-reference-object
---
@@ -3,7 +3,7 @@ id: 5f32db63eb37f7e17323f459
title: Build a Castle
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-nano-by-building-a-castle
url: freeCodeCamp/learn-nano-by-building-a-castle
dashedName: build-a-castle
---
@@ -3,7 +3,7 @@ id: 5f2c289f164c29556da632fd
title: Build a Mario Database
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-relational-databases-by-building-a-mario-database
url: freeCodeCamp/learn-relational-databases-by-building-a-mario-database
dashedName: build-a-mario-database
---
@@ -3,7 +3,7 @@ id: 602da0c222201c65d2a019f5
title: "Build a Student Database: Part 1"
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-sql-by-building-a-student-database-part-1
url: freeCodeCamp/learn-sql-by-building-a-student-database-part-1
dashedName: build-a-student-database-part-1
---
@@ -3,7 +3,7 @@ id: 618590adb0730ca724e37672
title: "Build a Student Database: Part 2"
challengeType: 12
helpCategory: Backend Development
url: https://github.com/freeCodeCamp/learn-sql-by-building-a-student-database-part-2
url: freeCodeCamp/learn-sql-by-building-a-student-database-part-2
dashedName: build-a-student-database-part-2
---
+1 -2
View File
@@ -20,8 +20,7 @@ describe('User token widget on settings page,', function () {
cy.visit(
'/learn/relational-database/learn-bash-by-building-a-boilerplate/build-a-boilerplate'
);
cy.get('[data-cy=start-codeally]').click();
cy.get('[data-cy=codeally-frame]').should('be.visible');
cy.contains('Start the course').click();
});
it('should allow you to delete your token', () => {