feat: release rdbms to production (#45169)

* fix: add cert to email for when all certs are earned

* fix: unhide rdbms from production

* fix: cert project input field

* feat: add cypress tests

* fix: message on project pages to lower expectations

* fix: update instructions

* fix: add quincy's suggestions

* fix: add beta label and reorder

* fix: utils test

* fix: move rdbms to bottom of settings

* fix: cypress tests

* Apply suggestions from code review

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

* fix: only drop seeded users webhook tokens

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
Tom
2022-03-04 04:08:09 -06:00
committed by GitHub
parent 68ad98f83d
commit 84c305ab08
28 changed files with 225 additions and 115 deletions

View File

@ -157,7 +157,8 @@ function sendCertifiedEmail(
isInfosecCertV7, isInfosecCertV7,
isSciCompPyCertV7, isSciCompPyCertV7,
isDataAnalysisPyCertV7, isDataAnalysisPyCertV7,
isMachineLearningPyCertV7 isMachineLearningPyCertV7,
isRelationalDatabaseCertV8
}, },
send$ send$
) { ) {
@ -172,7 +173,8 @@ function sendCertifiedEmail(
!isInfosecCertV7 || !isInfosecCertV7 ||
!isSciCompPyCertV7 || !isSciCompPyCertV7 ||
!isDataAnalysisPyCertV7 || !isDataAnalysisPyCertV7 ||
!isMachineLearningPyCertV7 !isMachineLearningPyCertV7 ||
!isRelationalDatabaseCertV8
) { ) {
return Observable.just(false); return Observable.just(false);
} }

View File

@ -411,7 +411,7 @@
} }
}, },
"relational-database": { "relational-database": {
"title": "Relational Database", "title": "Relational Database (Beta)",
"intro": [ "intro": [
"For these courses, you will use real developer tools and software including VS Code, PostgreSQL, and the Linux / Unix command line to complete interactive tutorials and build projects.", "For these courses, you will use real developer tools and software including VS Code, PostgreSQL, and the Linux / Unix command line to complete interactive tutorials and build projects.",
"These courses start off with basic Bash commands. Using the terminal, you will learn everything from navigating and manipulating a file system, scripting in Bash, all the way to advanced usage.", "These courses start off with basic Bash commands. Using the terminal, you will learn everything from navigating and manipulating a file system, scripting in Bash, all the way to advanced usage.",
@ -458,62 +458,62 @@
"title": "Learn Advanced Bash by Building a Kitty Ipsum Translator", "title": "Learn Advanced Bash by Building a Kitty Ipsum Translator",
"intro": [ "intro": [
"There's more to Bash commands than you might think.", "There's more to Bash commands than you might think.",
"In this 140 lesson course, you will learn some more complex commands, and the details of how commands work." "In this 140-lesson course, you will learn some more complex commands, and the details of how commands work."
] ]
}, },
"learn-bash-and-sql-by-building-a-bike-rental-shop": { "learn-bash-and-sql-by-building-a-bike-rental-shop": {
"title": "Learn Bash and SQL by Building a Bike Rental Shop", "title": "Learn Bash and SQL by Building a Bike Rental Shop",
"intro": [ "intro": [
"In this 210 lesson course, you will build an interactive Bash program that stores rental information for your bike rental shop using PostgreSQL." "In this 210-lesson course, you will build an interactive Bash program that stores rental information for your bike rental shop using PostgreSQL."
] ]
}, },
"learn-bash-by-building-a-boilerplate": { "learn-bash-by-building-a-boilerplate": {
"title": "Learn Bash by Building a Boilerplate", "title": "Learn Bash by Building a Boilerplate",
"intro": [ "intro": [
"The terminal allows you to send text commands to your computer that can manipulate the file system, run programs, automate tasks, and much more.", "The terminal allows you to send text commands to your computer that can manipulate the file system, run programs, automate tasks, and much more.",
"In this 170 lesson course, you will learn basic commands by creating a website boilerplate using only the command line." "In this 170-lesson course, you will learn terminal commands by creating a website boilerplate using only the command line."
] ]
}, },
"learn-bash-scripting-by-building-five-programs": { "learn-bash-scripting-by-building-five-programs": {
"title": "Learn Bash Scripting by Building Five Programs", "title": "Learn Bash Scripting by Building Five Programs",
"intro": [ "intro": [
"Bash scripts combine terminal commands and logic into programs that can execute or automate tasks, and much more.", "Bash scripts combine terminal commands and logic into programs that can execute or automate tasks, and much more.",
"In this 220 lesson course, you will learn more terminal commands and how to use them within Bash scripts by creating five small programs." "In this 220-lesson course, you will learn more terminal commands and how to use them within Bash scripts by creating five small programs."
] ]
}, },
"learn-git-by-building-an-sql-reference-object": { "learn-git-by-building-an-sql-reference-object": {
"title": "Learn Git by Building an SQL Reference Object", "title": "Learn Git by Building an SQL Reference Object",
"intro": [ "intro": [
"Git is a version control system that keeps track of all the changes you make to your codebase.", "Git is a version control system that keeps track of all the changes you make to your codebase.",
"In this 240 lesson course, you will learn how Git keeps track of your code by creating an object containing commonly used SQL commands." "In this 240-lesson course, you will learn how Git keeps track of your code by creating an object containing commonly used SQL commands."
] ]
}, },
"learn-nano-by-building-a-castle": { "learn-nano-by-building-a-castle": {
"title": "Learn Nano by Building a Castle", "title": "Learn Nano by Building a Castle",
"intro": [ "intro": [
"Nano is a program that allows you to edit files right in the terminal.", "Nano is a program that allows you to edit files right in the terminal.",
"In this 40 lesson course, you will learn how to edit files in the terminal with Nano while building a castle." "In this 40-lesson course, you will learn how to edit files in the terminal with Nano while building a castle."
] ]
}, },
"learn-relational-databases-by-building-a-mario-database": { "learn-relational-databases-by-building-a-mario-database": {
"title": "Learn Relational Databases by Building a Mario Database", "title": "Learn Relational Databases by Building a Mario Database",
"intro": [ "intro": [
"A relational database organizes data into tables that are linked together through relationships.", "A relational database organizes data into tables that are linked together through relationships.",
"In this 165 lesson course, you will learn the basics of a relational database by creating a PostgreSQL database filled with video game characters." "In this 165-lesson course, you will learn the basics of a relational database by creating a PostgreSQL database filled with video game characters."
] ]
}, },
"learn-sql-by-building-a-student-database-part-1": { "learn-sql-by-building-a-student-database-part-1": {
"title": "Learn SQL by Building a Student Database: Part 1", "title": "Learn SQL by Building a Student Database: Part 1",
"intro": [ "intro": [
"SQL, or Structured Query Language, is the language for communicating with a relational database.", "SQL, or Structured Query Language, is the language for communicating with a relational database.",
"In this 140 lesson course, you will create a Bash script that uses SQL to enter information about your computer science students into PostgreSQL." "In this 140-lesson course, you will create a Bash script that uses SQL to enter information about your computer science students into PostgreSQL."
] ]
}, },
"learn-sql-by-building-a-student-database-part-2": { "learn-sql-by-building-a-student-database-part-2": {
"title": "Learn SQL by Building a Student Database: Part 2", "title": "Learn SQL by Building a Student Database: Part 2",
"intro": [ "intro": [
"SQL join commands are used to combine information from multiple tables in a relational database", "SQL join commands are used to combine information from multiple tables in a relational database",
"In this 140 lesson course, you will complete your student database while diving deeper into SQL commands." "In this 140-lesson course, you will complete your student database while diving deeper into SQL commands."
] ]
} }
} }

View File

@ -298,7 +298,7 @@
"help-translate": "We are still translating the following certifications.", "help-translate": "We are still translating the following certifications.",
"help-translate-link": "Help us translate.", "help-translate-link": "Help us translate.",
"project-preview-title": "Here's a preview of what you will build", "project-preview-title": "Here's a preview of what you will build",
"github-required": "A <0>GitHub</0> account is required to run the project. You will need to create one if you haven't already.", "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.",
"step-1": "Step 1: Complete the project", "step-1": "Step 1: Complete the project",
"step-2": "Step 2: Submit your code", "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.", "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.",

View File

@ -27,7 +27,7 @@ import {
import { User } from '../redux/prop-types'; import { User } from '../redux/prop-types';
import { submitNewAbout, updateUserFlag, verifyCert } from '../redux/settings'; import { submitNewAbout, updateUserFlag, verifyCert } from '../redux/settings';
const { apiLocation, deploymentEnv } = envData; const { apiLocation } = envData;
// TODO: update types for actions // TODO: update types for actions
interface ShowSettingsProps { interface ShowSettingsProps {
@ -202,8 +202,8 @@ export function ShowSettings(props: ShowSettingsProps): JSX.Element {
username={username} username={username}
verifyCert={verifyCert} verifyCert={verifyCert}
/> />
{deploymentEnv == 'staging' && <Spacer />} <Spacer />
{deploymentEnv == 'staging' && <WebhookToken />} <WebhookToken />
<Spacer /> <Spacer />
<DangerZone /> <DangerZone />
</main> </main>

View File

@ -74,7 +74,7 @@ class WebhookToken extends Component<WebhookTokenProps, WebhookTokenState> {
return isChallengePage ? ( return isChallengePage ? (
<> <>
{!webhookToken && ( {!webhookToken && (
<div className='alert alert-info'> <div className='alert alert-info' data-cy='webhook-challenge-page'>
<p>{t('webhook-token.create-p1')}</p> <p>{t('webhook-token.create-p1')}</p>
<Spacer /> <Spacer />
<Button <Button
@ -89,7 +89,10 @@ class WebhookToken extends Component<WebhookTokenProps, WebhookTokenState> {
)} )}
</> </>
) : ( ) : (
<div className='webhook-token text-center'> <div
className='webhook-token text-center'
data-cy='webhook-settings-page'
>
<FullWidthRow> <FullWidthRow>
<Panel className='webhook-panel'> <Panel className='webhook-panel'>
<Panel.Heading>{t('webhook-token.title')}</Panel.Heading> <Panel.Heading>{t('webhook-token.title')}</Panel.Heading>

View File

@ -1,7 +1,7 @@
import { SuperBlocks } from '../../../config/certification-settings'; import { SuperBlocks } from '../../../config/certification-settings';
import envData from '../../../config/env.json'; import envData from '../../../config/env.json';
const { deploymentEnv, showNewCurriculum, showUpcomingChanges } = envData; const { showNewCurriculum, showUpcomingChanges } = envData;
const responsiveWebBase = const responsiveWebBase =
'/learn/responsive-web-design/responsive-web-design-projects'; '/learn/responsive-web-design/responsive-web-design-projects';
@ -455,44 +455,6 @@ const certMap = [
} }
] ]
}, },
{
id: '606243f50267e718b1e755f4',
title: 'Relational Database',
certSlug: 'relational-database-v8',
flag: 'isRelationalDatabaseCertV8',
projects: [
{
id: '5f1a4ef5d5d6b5ab580fc6ae',
title: 'Celestial Bodies Database',
link: `${relationalDatabaseBase}/build-a-celestial-bodies-database-project/build-a-celestial-bodies-database`,
certSlug: 'relational-database-v8'
},
{
id: '5f9771307d4d22b9d2b75a94',
title: 'World Cup Database',
link: `${relationalDatabaseBase}/build-a-world-cup-database-project/build-a-world-cup-database`,
certSlug: 'relational-database-v8'
},
{
id: '5f87ac112ae598023a42df1a',
title: 'Salon Appointment Scheduler',
link: `${relationalDatabaseBase}/build-a-salon-appointment-scheduler-project/build-a-salon-appointment-scheduler`,
certSlug: 'relational-database-v8'
},
{
id: '602d9ff222201c65d2a019f2',
title: 'Periodic Table Database',
link: `${relationalDatabaseBase}/build-a-periodic-table-database-project/build-a-periodic-table-database`,
certSlug: 'relational-database-v8'
},
{
id: '602da04c22201c65d2a019f4',
title: 'Number Guessing Game',
link: `${relationalDatabaseBase}/build-a-number-guessing-game-project/build-a-number-guessing-game`,
certSlug: 'relational-database-v8'
}
]
},
{ {
id: '561add10cb82ac38a17523bc', id: '561add10cb82ac38a17523bc',
title: 'Back End Development and APIs', title: 'Back End Development and APIs',
@ -721,6 +683,44 @@ const certMap = [
certSlug: 'machine-learning-with-python-v7' certSlug: 'machine-learning-with-python-v7'
} }
] ]
},
{
id: '606243f50267e718b1e755f4',
title: 'Relational Database',
certSlug: 'relational-database-v8',
flag: 'isRelationalDatabaseCertV8',
projects: [
{
id: '5f1a4ef5d5d6b5ab580fc6ae',
title: 'Celestial Bodies Database',
link: `${relationalDatabaseBase}/build-a-celestial-bodies-database-project/build-a-celestial-bodies-database`,
certSlug: 'relational-database-v8'
},
{
id: '5f9771307d4d22b9d2b75a94',
title: 'World Cup Database',
link: `${relationalDatabaseBase}/build-a-world-cup-database-project/build-a-world-cup-database`,
certSlug: 'relational-database-v8'
},
{
id: '5f87ac112ae598023a42df1a',
title: 'Salon Appointment Scheduler',
link: `${relationalDatabaseBase}/build-a-salon-appointment-scheduler-project/build-a-salon-appointment-scheduler`,
certSlug: 'relational-database-v8'
},
{
id: '602d9ff222201c65d2a019f2',
title: 'Periodic Table Database',
link: `${relationalDatabaseBase}/build-a-periodic-table-database-project/build-a-periodic-table-database`,
certSlug: 'relational-database-v8'
},
{
id: '602da04c22201c65d2a019f4',
title: 'Number Guessing Game',
link: `${relationalDatabaseBase}/build-a-number-guessing-game-project/build-a-number-guessing-game`,
certSlug: 'relational-database-v8'
}
]
} }
] as const; ] as const;
@ -745,12 +745,7 @@ certMap.forEach(cert => {
if (cert.title !== 'Legacy Full Stack') { if (cert.title !== 'Legacy Full Stack') {
if (cert.title.startsWith('Legacy')) { if (cert.title.startsWith('Legacy')) {
legacyProjectMap[cert.title] = cert.projects; legacyProjectMap[cert.title] = cert.projects;
} else if ( } else {
cert.title.startsWith('Relational') &&
deploymentEnv == 'staging'
) {
projectMap[cert.title] = cert.projects;
} else if (!cert.title.startsWith('Relational')) {
projectMap[cert.title] = cert.projects; projectMap[cert.title] = cert.projects;
} }
} }

View File

@ -257,7 +257,7 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps, ShowCodeAllyState> {
<div className='ca-description'> <div className='ca-description'>
<Trans i18nKey='learn.github-required'> <Trans i18nKey='learn.github-required'>
<a <a
href='https://github.com' href='https://github.com/join'
rel='noopener noreferrer' rel='noopener noreferrer'
target='_blank' target='_blank'
title={t('learn.github-link')} title={t('learn.github-link')}

View File

@ -6,7 +6,8 @@ import {
backend, backend,
backEndProject, backEndProject,
frontEndProject, frontEndProject,
pythonProject pythonProject,
codeAllyCert
} from '../../../../utils/challenge-types'; } from '../../../../utils/challenge-types';
import { Form, ValidatedValues } from '../../../components/formHelpers'; import { Form, ValidatedValues } from '../../../components/formHelpers';
@ -101,6 +102,12 @@ export class SolutionForm extends Component<FormProps> {
: 'https://replit.com/@camperbot/hello'); : 'https://replit.com/@camperbot/hello');
break; break;
case codeAllyCert:
formFields = solutionField;
options.isEditorLinkAllowed = true;
solutionLink = solutionLink + 'https://your-git-repo.url/files';
break;
default: default:
formFields = solutionField; formFields = solutionField;
solutionLink = solutionLink =

View File

@ -10,7 +10,7 @@ const {
getChallengesDirForLang getChallengesDirForLang
} = require('../../curriculum/getChallenges'); } = require('../../curriculum/getChallenges');
const { curriculumLocale, deploymentEnv } = envData; const { curriculumLocale } = envData;
exports.localeChallengesRootDir = getChallengesDirForLang(curriculumLocale); exports.localeChallengesRootDir = getChallengesDirForLang(curriculumLocale);
@ -38,12 +38,6 @@ exports.replaceChallengeNode = () => {
exports.buildChallenges = async function buildChallenges() { exports.buildChallenges = async function buildChallenges() {
const curriculum = await getChallengesForLang(curriculumLocale); const curriculum = await getChallengesForLang(curriculumLocale);
// temp removal of rdbms from production
if (deploymentEnv !== 'staging') {
delete curriculum['13-relational-databases'];
}
const superBlocks = Object.keys(curriculum); const superBlocks = Object.keys(curriculum);
const blocks = superBlocks const blocks = superBlocks
.map(superBlock => curriculum[superBlock].blocks) .map(superBlock => curriculum[superBlock].blocks)

View File

@ -20,6 +20,7 @@ exports.backend = backend;
exports.frontEndProject = frontEndProject; exports.frontEndProject = frontEndProject;
exports.backEndProject = backEndProject; exports.backEndProject = backEndProject;
exports.pythonProject = pythonProject; exports.pythonProject = pythonProject;
exports.codeAllyCert = codeAllyCert;
exports.challengeTypes = { exports.challengeTypes = {
html, html,

View File

@ -13,11 +13,11 @@ This is one of the required projects to earn your certification. For this projec
# --instructions-- # --instructions--
**Important:** After you pass all the project tests, save a dump of your database into a `number_guessers.sql` file, as well as your whole `number_guessing_game` folder, so you can complete step 2. There will be instructions how to do that within the virtual machine. **Important:** After you pass all the project tests, save a dump of your database into a `number_guess.sql` file, as well as your whole `number_guess.sh` file, so you can complete step 2. There will be instructions how to do that within the virtual machine.
# --notes-- # --notes--
Required files: `number_guessers.sql`, and the whole `number_guessing_game` folder Required files: `number_guess.sql`, `number_guess.sh`
# --hints-- # --hints--

View File

@ -13,11 +13,11 @@ This is one of the required projects to earn your certification. For this projec
# --instructions-- # --instructions--
**Important:** After you pass all the project tests, save a dump of your database into a `elements.sql` file, as well as your whole `periodic_table` folder, so you can complete step 2. There will be instructions how to do that within the virtual machine. **Important:** After you pass all the project tests, save a dump of your database into a `periodic_table.sql` file, as well as your `element.sh` file, so you can complete step 2. There will be instructions how to do that within the virtual machine.
# --notes-- # --notes--
Required files: `elements.sql`, and the whole `periodic_table` folder Required files: `periodic_table.sql`, `element.sh`
# --hints-- # --hints--

View File

@ -9,7 +9,7 @@ dashedName: build-a-kitty-ipsum-translator
# --description-- # --description--
In this 140 lesson course, you will learn some more complex commands, and the details of how commands work. In this 140-lesson course, you will learn some more complex commands, and the details of how commands work.
# --instructions-- # --instructions--

View File

@ -9,7 +9,7 @@ dashedName: build-a-bike-rental-shop
# --description-- # --description--
In this 210 lesson course, you will build an interactive Bash program that stores rental information for your bike rental shop using PostgreSQL. In this 210-lesson course, you will build an interactive Bash program that stores rental information for your bike rental shop using PostgreSQL.
# --instructions-- # --instructions--

View File

@ -9,7 +9,7 @@ dashedName: build-a-boilerplate
# --description-- # --description--
In this 170 lesson course, you will learn basic commands by creating a website boilerplate using only the command line. In this 170-lesson course, you will learn terminal commands by creating a website boilerplate using only the command line.
# --instructions-- # --instructions--

View File

@ -9,7 +9,7 @@ dashedName: build-five-programs
# --description-- # --description--
In this 220 lesson course, you will learn more terminal commands and how to use them within Bash scripts by creating five small programs. In this 220-lesson course, you will learn more terminal commands and how to use them within Bash scripts by creating five small programs.
# --instructions-- # --instructions--

View File

@ -9,7 +9,7 @@ dashedName: build-an-sql-reference-object
# --description-- # --description--
In this 240 lesson course, you will learn how Git keeps track of your code by creating an object containing commonly used SQL commands. In this 240-lesson course, you will learn how Git keeps track of your code by creating an object containing commonly used SQL commands.
# --instructions-- # --instructions--

View File

@ -9,7 +9,7 @@ dashedName: build-a-castle
# --description-- # --description--
In this 40 lesson course, you will learn how to edit files in the terminal with Nano while building a castle. In this 40-lesson course, you will learn how to edit files in the terminal with Nano while building a castle.
# --instructions-- # --instructions--

View File

@ -9,7 +9,7 @@ dashedName: build-a-mario-database
# --description-- # --description--
In this 165 lesson course, you will learn the basics of a relational database by creating a PostgreSQL database filled with video game characters. In this 165-lesson course, you will learn the basics of a relational database by creating a PostgreSQL database filled with video game characters.
# --instructions-- # --instructions--

View File

@ -9,7 +9,7 @@ dashedName: build-a-student-database-part-1
# --description-- # --description--
In this 140 lesson course, you will create a Bash script that uses SQL to enter information about your computer science students into PostgreSQL. In this 140-lesson course, you will create a Bash script that uses SQL to enter information about your computer science students into PostgreSQL.
# --instructions-- # --instructions--

View File

@ -9,7 +9,7 @@ dashedName: build-a-student-database-part-2
# --description-- # --description--
In this 140 lesson course, you will complete your student database while diving deeper into SQL commands. In this 140-lesson course, you will complete your student database while diving deeper into SQL commands.
# --instructions-- # --instructions--

View File

@ -25,19 +25,19 @@ const superBlockToOrder = {
'javascript-algorithms-and-data-structures': 1, 'javascript-algorithms-and-data-structures': 1,
'front-end-development-libraries': 2, 'front-end-development-libraries': 2,
'data-visualization': 3, 'data-visualization': 3,
'relational-database': 4, 'back-end-development-and-apis': 4,
'back-end-development-and-apis': 5, 'quality-assurance': 5,
'quality-assurance': 6, 'scientific-computing-with-python': 6,
'scientific-computing-with-python': 7, 'data-analysis-with-python': 7,
'data-analysis-with-python': 8, 'information-security': 8,
'information-security': 9, 'machine-learning-with-python': 9,
'machine-learning-with-python': 10, 'coding-interview-prep': 10,
'coding-interview-prep': 11 'relational-database': 12
}; };
const superBlockToNewOrder = { const superBlockToNewOrder = {
...superBlockToOrder, ...superBlockToOrder,
'2022/responsive-web-design': 12 '2022/responsive-web-design': 11
}; };
function getSuperOrder( function getSuperOrder(

View File

@ -25,14 +25,14 @@ describe('getSuperOrder', () => {
expect(getSuperOrder('javascript-algorithms-and-data-structures')).toBe(1); expect(getSuperOrder('javascript-algorithms-and-data-structures')).toBe(1);
expect(getSuperOrder('front-end-development-libraries')).toBe(2); expect(getSuperOrder('front-end-development-libraries')).toBe(2);
expect(getSuperOrder('data-visualization')).toBe(3); expect(getSuperOrder('data-visualization')).toBe(3);
expect(getSuperOrder('relational-database')).toBe(4); expect(getSuperOrder('back-end-development-and-apis')).toBe(4);
expect(getSuperOrder('back-end-development-and-apis')).toBe(5); expect(getSuperOrder('quality-assurance')).toBe(5);
expect(getSuperOrder('quality-assurance')).toBe(6); expect(getSuperOrder('scientific-computing-with-python')).toBe(6);
expect(getSuperOrder('scientific-computing-with-python')).toBe(7); expect(getSuperOrder('data-analysis-with-python')).toBe(7);
expect(getSuperOrder('data-analysis-with-python')).toBe(8); expect(getSuperOrder('information-security')).toBe(8);
expect(getSuperOrder('information-security')).toBe(9); expect(getSuperOrder('machine-learning-with-python')).toBe(9);
expect(getSuperOrder('machine-learning-with-python')).toBe(10); expect(getSuperOrder('coding-interview-prep')).toBe(10);
expect(getSuperOrder('coding-interview-prep')).toBe(11); expect(getSuperOrder('relational-database')).toBe(12);
}); });
it('returns a different order if passed the option showNewCurriculum: true', () => { it('returns a different order if passed the option showNewCurriculum: true', () => {
@ -53,36 +53,36 @@ describe('getSuperOrder', () => {
expect( expect(
getSuperOrder('data-visualization', { showNewCurriculum: true }) getSuperOrder('data-visualization', { showNewCurriculum: true })
).toBe(3); ).toBe(3);
expect(
getSuperOrder('relational-database', { showNewCurriculum: true })
).toBe(4);
expect( expect(
getSuperOrder('back-end-development-and-apis', { getSuperOrder('back-end-development-and-apis', {
showNewCurriculum: true showNewCurriculum: true
}) })
).toBe(5); ).toBe(4);
expect( expect(
getSuperOrder('quality-assurance', { showNewCurriculum: true }) getSuperOrder('quality-assurance', { showNewCurriculum: true })
).toBe(6); ).toBe(5);
expect( expect(
getSuperOrder('scientific-computing-with-python', { getSuperOrder('scientific-computing-with-python', {
showNewCurriculum: true showNewCurriculum: true
}) })
).toBe(7); ).toBe(6);
expect( expect(
getSuperOrder('data-analysis-with-python', { showNewCurriculum: true }) getSuperOrder('data-analysis-with-python', { showNewCurriculum: true })
).toBe(8); ).toBe(7);
expect( expect(
getSuperOrder('information-security', { showNewCurriculum: true }) getSuperOrder('information-security', { showNewCurriculum: true })
).toBe(9); ).toBe(8);
expect( expect(
getSuperOrder('machine-learning-with-python', { showNewCurriculum: true }) getSuperOrder('machine-learning-with-python', { showNewCurriculum: true })
).toBe(10); ).toBe(9);
expect( expect(
getSuperOrder('coding-interview-prep', { showNewCurriculum: true }) getSuperOrder('coding-interview-prep', { showNewCurriculum: true })
).toBe(11); ).toBe(10);
expect( expect(
getSuperOrder('2022/responsive-web-design', { showNewCurriculum: true }) getSuperOrder('2022/responsive-web-design', { showNewCurriculum: true })
).toBe(11);
expect(
getSuperOrder('relational-database', { showNewCurriculum: true })
).toBe(12); ).toBe(12);
}); });
}); });

View File

@ -17,7 +17,8 @@ const certifications = [
'Data Analysis with Python', 'Data Analysis with Python',
'Information Security', 'Information Security',
'Machine Learning with Python', 'Machine Learning with Python',
'Responsive Web Design (Beta)' 'Responsive Web Design (Beta)',
'Relational Database (Beta)'
]; ];
describe('Landing page', () => { describe('Landing page', () => {

View File

@ -0,0 +1,35 @@
describe('CodeAlly cert challenge', function () {
describe('before completing the project', function () {
before(() => {
cy.exec('npm run seed');
cy.login();
cy.visit(
'/learn/relational-database/build-a-celestial-bodies-database-project/build-a-celestial-bodies-database'
);
});
it('should not allow you to submit a URL', function () {
cy.get('input[name="solution"]')
.type('https://example.com')
.type('{enter}');
cy.contains('You must complete the project first.');
});
});
describe('after completing the project', function () {
before(() => {
cy.exec('npm run seed:certified-user');
cy.login();
cy.visit(
'/learn/relational-database/build-a-celestial-bodies-database-project/build-a-celestial-bodies-database'
);
});
it('should allow you to submit a URL', function () {
cy.get('input[name="solution"]')
.type('https://example.com')
.type('{enter}');
cy.get('.completion-modal-body').should('exist');
});
});
});

View File

@ -0,0 +1,58 @@
describe('Webhook token component', function () {
describe('while signed out', function () {
describe('on CodeAlly project page', function () {
before(() => {
cy.exec('npm run seed');
cy.visit(
'/learn/relational-database/build-a-celestial-bodies-database-project/build-a-celestial-bodies-database'
);
});
it('should not render', function () {
cy.get('[data-cy=webhook-challenge-page]').should('not.exist');
cy.get('.webhook-token').should('not.exist');
});
});
});
describe('while signed in', function () {
describe('on CodeAlly project page', function () {
beforeEach(() => {
cy.exec('npm run seed');
cy.login();
cy.visit(
'/learn/relational-database/build-a-celestial-bodies-database-project/build-a-celestial-bodies-database'
);
});
it('should render', function () {
cy.get('[data-cy=webhook-challenge-page]').should('exist');
});
it('should allow you to create a token', function () {
cy.contains('Create a new token').click();
cy.contains('You have successfully created a new token.');
});
});
describe('on settings page', function () {
beforeEach(() => {
cy.exec('npm run seed');
cy.login();
cy.visit('/settings');
});
it('should render', function () {
cy.get('[data-cy=webhook-settings-page]').should('exist');
});
it('should allow you to create and delete a token', function () {
cy.contains('Create a new token').click();
cy.contains('You have successfully created a new token.');
cy.contains('Delete my token').click();
cy.contains('Yes please, I would like to delete my token').click();
cy.contains('Your token has been deleted');
});
});
});
});

View File

@ -11,7 +11,6 @@ const superBlockNames = [
'JavaScript Algorithms and Data Structures Certification', 'JavaScript Algorithms and Data Structures Certification',
'Front End Development Libraries Certification', 'Front End Development Libraries Certification',
'Data Visualization Certification', 'Data Visualization Certification',
'Relational Database Certification',
'Back End Development and APIs Certification', 'Back End Development and APIs Certification',
'Quality Assurance Certification', 'Quality Assurance Certification',
'Scientific Computing with Python Certification', 'Scientific Computing with Python Certification',
@ -19,7 +18,8 @@ const superBlockNames = [
'Information Security Certification', 'Information Security Certification',
'Machine Learning with Python Certification', 'Machine Learning with Python Certification',
'Coding Interview Prep (Thousands of hours of challenges)', 'Coding Interview Prep (Thousands of hours of challenges)',
'Responsive Web Design (Beta) Certification' 'Responsive Web Design (Beta) Certification',
'Relational Database (Beta) Certification'
]; ];
describe('Learn Landing page (not logged in)', () => { describe('Learn Landing page (not logged in)', () => {

View File

@ -153,7 +153,20 @@ MongoClient.connect(MONGOHQ_URL, { useNewUrlParser: true }, (err, client) => {
const db = client.db('freecodecamp'); const db = client.db('freecodecamp');
const user = db.collection('user'); const user = db.collection('user');
const dropWebhookTokens = async function () {
await db.collection('WebhookToken').deleteMany({
userId: {
$in: [
ObjectId('5fa2db00a25c1c1fa49ce067'),
ObjectId('5bd30e0f1caf6ac3ddddddb5'),
ObjectId('5bd30e0f1caf6ac3ddddddb9')
]
}
});
};
if (process.argv[2] === 'certUser') { if (process.argv[2] === 'certUser') {
dropWebhookTokens();
user.deleteMany( user.deleteMany(
{ {
_id: { _id: {
@ -179,6 +192,7 @@ MongoClient.connect(MONGOHQ_URL, { useNewUrlParser: true }, (err, client) => {
} }
); );
} else { } else {
dropWebhookTokens();
user.deleteMany( user.deleteMany(
{ {
_id: { _id: {