revert: (test, e2e) test suit for cypress (#42488)

This reverts commit 22b45761a7.
This commit is contained in:
Mrugesh Mohapatra
2021-06-14 23:44:43 +05:30
committed by GitHub
parent 3fc6877bb0
commit 3130265991
35 changed files with 55 additions and 367 deletions

View File

@ -0,0 +1,41 @@
/* global cy */
const locations = {
index:
'learn/apis-and-microservices/managing-packages-with-npm/' +
'how-to-use-package-json-the-core-of-any-node-js-project-or-npm-package'
};
const selectors = {
defaultOutput: '.output-text',
input: 'input[name="solution"]'
};
const unhandledErrorMessage = 'Something is not quite right';
const runningOutput = '// running tests';
const finishedOutput = '// tests completed';
describe('Backend challenge', function () {
it('renders', () => {
cy.visit(locations.index);
cy.title().should(
'eq',
'Managing Packages with Npm - How to Use package.json, the Core of Any' +
' Node.js Project or npm Package | Learn | freeCodeCamp.org'
);
});
it('does not generate unhandled errors on submission', () => {
cy.visit(locations.index);
cy.get(selectors.input)
.type('https://example.com')
.type('{enter}')
.then(() => {
cy.get(selectors.defaultOutput)
.contains(runningOutput)
.contains(finishedOutput);
cy.contains(unhandledErrorMessage).should('not.exist');
});
});
});

View File

@ -0,0 +1,64 @@
/* global cy */
const selectors = {
defaultOutput: '.output-text',
editor: '.monaco-editor',
hotkeys: '.default-layout > div',
runTestsButton: 'button:contains("Run the Tests")'
};
const locations = {
index:
'/learn/responsive-web-design/basic-html-and-html5/' +
'say-hello-to-html-elements'
};
const defaultOutput = `
/**
* Your test output will go here
*/`;
const runningOutput = '// running tests';
const finishedOutput = '// tests completed';
describe('Classic challenge', function () {
before(() => {
cy.visit(locations.index);
});
it('renders the default output text', () => {
cy.title().should(
'eq',
'Learn Basic HTML and HTML5: Say Hello to HTML Elements |' +
' freeCodeCamp.org'
);
cy.get(selectors.defaultOutput).contains(defaultOutput);
});
it('shows test output when the tests are run', () => {
// first wait for the editor to load
cy.get(selectors.editor, { timeout: 15000 });
cy.get(selectors.runTestsButton)
.click()
.then(() => {
cy.get(selectors.defaultOutput)
.contains(runningOutput)
.contains(finishedOutput);
});
});
it('shows test output when the tests are triggered by the keyboard', () => {
// first wait for the editor to load
cy.get(selectors.editor, {
timeout: 15000
});
cy.get(selectors.hotkeys)
.focus()
.type('{ctrl}{enter}')
.then(() => {
cy.get(selectors.defaultOutput)
.contains(runningOutput)
.contains(finishedOutput);
});
});
});

View File

@ -0,0 +1,52 @@
/* global cy */
const projects = {
superBlock: 'machine-learning-with-python',
block: 'machine-learning-with-python-projects',
challenges: [
{
slug: 'book-recommendation-engine-using-knn',
nextChallengeText: 'Linear Regression Health Costs Calculator'
},
{
slug: 'cat-and-dog-image-classifier',
nextChallengeText: 'Book Recommendation Engine using KNN'
},
{
slug: 'linear-regression-health-costs-calculator',
nextChallengeText: 'Neural Network SMS Text Classifier'
},
{
slug: 'neural-network-sms-text-classifier',
nextChallengeText: 'Find the Symmetric Difference'
},
{
slug: 'rock-paper-scissors',
nextChallengeText: 'Cat and Dog Image Classifier'
}
]
};
describe('project submission', () => {
// NOTE: this will fail once challenge tests are added.
it('Should be possible to submit Python projects', () => {
const { superBlock, block, challenges } = projects;
challenges.forEach(({ slug }) => {
const url = `/learn/${superBlock}/${block}/${slug}`;
cy.visit(url);
cy.get('#dynamic-front-end-form')
.get('#solution')
.type('https://replit.com/@camperbot/python-project#main.py');
cy.contains("I've completed this challenge").click();
cy.contains('Go to next challenge');
// clicking on 'Go to next challenge' seems to have caused flakiness, so
// it's commented out until we figure out why.
// cy.contains('Go to next challenge').click();
// The next two commands are to confirm that go to next challenge has
// moved us to the expected challenge before we loop again.
// cy.get('.title-text').should('include.text', nextChallengeText);
// cy.url().should('not.have.string', url);
});
});
});

View File

@ -0,0 +1,19 @@
/* global cy */
describe('Certification intro page', () => {
before(() => {
cy.clearCookies();
cy.login();
cy.visit('/learn/coding-interview-prep');
});
it('Should render', () => {
cy.contains(
"If you're looking for free coding exercises to prepare for your next job interview, we've got you covered."
).should('be.visible');
});
it('Title should not include the word "Certification"', () => {
cy.title().should('eq', 'Coding Interview Prep | freeCodeCamp.org');
});
});

View File

@ -0,0 +1,31 @@
/* global cy */
const selectors = {
footer: '.site-footer'
};
describe('Footer', () => {
it('Should render on landing page', () => {
cy.visit('/');
cy.get(selectors.footer).should('be.visible');
});
it('Should render on learn page', () => {
cy.visit('/learn');
cy.get(selectors.footer).should('be.visible');
cy.visit('/learn/');
cy.get(selectors.footer).should('be.visible');
});
it('Should render on superblock page', () => {
cy.visit('/learn/responsive-web-design/');
cy.get(selectors.footer).should('be.visible');
});
it('Should not render on challenge page', () => {
cy.visit(
'/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements'
);
cy.get(selectors.footer).should('not.exist');
});
});

View File

@ -0,0 +1,36 @@
/* global cy */
describe('Help Button', () => {
it('should be visible', () => {
cy.visit(
'/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements'
);
cy.get('#get-help-dropdown').scrollIntoView().should('be.visible');
});
it('should toggle the dropdown menu', () => {
cy.get('#get-help-dropdown').scrollIntoView().click();
cy.get('ul[role="menu"]').should('be.visible');
});
it('should render three links when video is available', () => {
cy.get('ul[role="menu"]').within(() => {
cy.get('a').should('have.length', 3);
cy.get('a').eq(0).contains('Get a Hint');
cy.get('a').eq(1).contains('Watch a Video');
cy.get('a').eq(2).contains('Ask for Help');
});
});
it('should render two links when video is not available', () => {
cy.visit(
'/learn/front-end-libraries/bootstrap/apply-the-default-bootstrap-button-style'
);
cy.get('#get-help-dropdown').scrollIntoView().click();
cy.get('ul[role="menu"]').within(() => {
cy.get('a').should('have.length', 2);
cy.get('a').eq(0).contains('Get a Hint');
cy.get('a').eq(1).contains('Ask for Help');
});
});
});

View File

@ -0,0 +1,109 @@
/* global cy */
const selectors = {
heading: "[data-test-label='landing-header']",
smallCallToAction: "[data-test-label='landing-small-cta']",
navigationLinks: '.nav-list',
avatarContainer: '.avatar-container',
defaultAvatar: '.avatar-container',
menuButton: '.toggle-button-nav',
avatarImage: '.avatar-container .avatar'
};
let appHasStarted;
function spyOnListener(win) {
const addListener = win.EventTarget.prototype.addEventListener;
win.EventTarget.prototype.addEventListener = function (name) {
if (name === 'click') {
appHasStarted = true;
win.EventTarget.prototype.addEventListener = addListener;
}
return addListener.apply(this, arguments);
};
}
function waitForAppStart() {
return new Promise(resolve => {
const isReady = () => {
if (appHasStarted) {
return resolve();
}
return setTimeout(isReady, 0);
};
isReady();
});
}
describe('Navbar', () => {
beforeEach(() => {
appHasStarted = false;
cy.visit('/', {
onBeforeLoad: spyOnListener
}).then(waitForAppStart);
cy.viewport(1300, 660);
});
it('Should render properly', () => {
cy.get('#universal-nav').should('be.visible');
cy.get('#universal-nav').should('have.class', 'universal-nav');
});
it(
'Should take user to learn page when clicked on ' + 'the freeCodeCamp logo',
() => {
cy.get('.universal-nav-middle').within(() => {
cy.get('svg').click();
});
cy.url().should('include', '/learn');
}
);
it('Should have a "Sign in" button', () => {
cy.contains("[data-test-label='landing-small-cta']", 'Sign in');
});
// have the curriculum and CTA on landing and /learn pages.
it(
'Should have `Radio`, `Forum`, and `Curriculum` links on landing and learn pages' +
'page when not signed in',
() => {
cy.get(selectors.menuButton).click();
cy.get(selectors.navigationLinks).contains('Forum');
cy.get(selectors.navigationLinks).contains('Curriculum').click();
cy.url().should('include', '/learn');
cy.get(selectors.navigationLinks).contains('Curriculum');
cy.get(selectors.navigationLinks).contains('Forum');
cy.get(selectors.navigationLinks).contains('Radio');
}
);
it(
'Should have `Sign in` link on landing and learn pages' +
' when not signed in',
() => {
cy.contains(selectors.smallCallToAction, 'Sign in');
cy.get(selectors.menuButton).click();
cy.get(selectors.navigationLinks).contains('Curriculum').click();
cy.contains(selectors.smallCallToAction, 'Sign in');
}
);
it('Should have `Profile` link when user is signed in', () => {
cy.login();
cy.get(selectors.menuButton).click();
cy.get(selectors.navigationLinks).contains('Profile').click();
cy.url().should('include', '/developmentuser');
});
it('Should have a profile image with class `default-border`', () => {
cy.login();
cy.get(selectors.avatarContainer).should('have.class', 'default-border');
cy.get(selectors.defaultAvatar).should('exist');
});
it('Should have a profile image with dimensions that are <= 31px', () => {
cy.login();
cy.get(selectors.avatarImage).invoke('width').should('lte', 31);
cy.get(selectors.avatarImage).invoke('height').should('lte', 31);
});
});

View File

@ -0,0 +1,77 @@
/* global cy */
const search = query => {
cy.get('.ais-SearchBox').within(() => {
cy.get('input').type(query);
});
cy.wait(300);
};
const clear = () => {
cy.get('.ais-SearchBox').within(() => {
cy.get('input').clear();
});
};
describe('Search bar', () => {
before(() => {
cy.visit('/');
});
beforeEach(() => {
clear();
});
it('Should render properly', () => {
cy.get('.ais-SearchBox').should('be.visible');
});
it('Should accept input and display hits', () => {
search('freeCodeCamp');
cy.get('.ais-Hits-list').children().should('to.have.length.of.at.least', 1);
});
it('Should clear hits when input is cleared', () => {
search('freeCodeCamp');
cy.get('.ais-Hits-list').children().should('to.have.length.of.at.least', 1);
clear();
cy.get('div.ais-Hits').should('not.exist');
});
it('Should show up to 8 hits when height >= 768px', () => {
cy.viewport(1300, 768);
search('freeCodeCamp');
cy.get('.ais-Hits-list').children().should('to.have.length.of', 8);
});
it('Should show up to 5 hits when height < 768px', () => {
cy.viewport(1300, 767);
search('freeCodeCamp');
cy.get('.ais-Hits-list').children().should('to.have.length.of', 5);
});
it('Should show no hits for queries that do not exist in the Algolia index', () => {
search('testtttt');
cy.get('.ais-Hits-list').children().should('to.have.length.of', 0);
cy.contains('No tutorials found');
});
it('Should not redirect to the News search page if there are no hits', () => {
search('testtttt');
cy.get('.ais-SearchBox-form').submit();
cy.url('/');
});
});

View File

@ -0,0 +1,65 @@
/* global cy */
const selectors = {
donateSupport: {
firstTitle: '.donate-support h4:first-of-type b',
secondTitle: '.donate-support h4:last-of-type b',
firstText: '.donate-support p:first-of-type',
secondText: '.donate-support p:last-of-type',
link: '.donate-support a'
}
};
describe('Donate page', () => {
before(() => {
cy.clearCookies();
cy.exec('npm run seed');
cy.login();
cy.visit('/donate');
});
it('Should render', () => {
cy.title().should('eq', 'Support our nonprofit | freeCodeCamp.org');
});
it('Should display default amount and duration', () => {
cy.contains('Confirm your donation of $5 / month:').should('be.visible');
});
it('Should have support section', () => {
cy.contains(
'Want to make a bigger one-time donation, mail us a check, or give in other ways?'
).should('be.visible');
});
it('Support section should have support text', () => {
cy.contains(
selectors.donateSupport.firstTitle,
'Want to make a bigger one-time donation, mail us a check, or give in other ways?'
);
cy.contains(
selectors.donateSupport.secondTitle,
'Need help with your current or past donations?'
);
cy.contains(
selectors.donateSupport.firstText,
"Here are many other ways you can support our non-profit's mission."
);
cy.contains(
selectors.donateSupport.secondText,
'Forward a copy of your donation receipt to donors@freecodecamp.org and tell us how we can help.'
);
});
it('Support section should have donation link', () => {
cy.get(selectors.donateSupport.link).should(
'have.attr',
'href',
'https://www.freecodecamp.org/news/how-to-donate-to-free-code-camp'
);
});
it('Donor alert should not be visible for non-donor', () => {
cy.get('.alert-info').should('not.exist');
});
});

View File

@ -0,0 +1,45 @@
/* global cy */
const selectors = {
donateAlert: {
firstText: '.alert-info p:first-child',
secondText: '.alert-info p:last-child',
link: '.alert-info a'
}
};
describe('Donate page', () => {
before(() => {
cy.clearCookies();
cy.exec('npm run seed -- --donor');
cy.login();
cy.visit('/donate');
});
after(() => {
cy.exec('npm run seed');
});
it('Donor alert should be visible for donor', () => {
cy.get('.alert-info').should('be.visible');
});
it('Donor should see alert message', () => {
cy.contains(
selectors.donateAlert.firstText,
'Thank you for being a supporter of freeCodeCamp. You currently have a recurring donation.'
);
cy.contains(
selectors.donateAlert.lastText,
"Want to make a bigger one-time donation, mail us a check, or give in other ways? Here are many other ways you can support our non-profit's mission."
);
});
it('Donor alert section should have donation link', () => {
cy.get(selectors.donateAlert.link).should(
'have.attr',
'href',
'https://www.freecodecamp.org/news/how-to-donate-to-free-code-camp'
);
});
});

View File

@ -0,0 +1,45 @@
/* global cy */
describe('Donate page', () => {
before(() => {
cy.clearCookies();
cy.exec('npm run seed');
cy.login();
});
after(() => {
cy.exec('npm run seed');
});
const projects = [
'tribute-page',
'survey-form',
'product-landing-page',
'technical-documentation-page',
'personal-portfolio-webpage'
];
it('Should be able to submit projects', () => {
const submitProject = str => {
cy.visit(
`/learn/responsive-web-design/responsive-web-design-projects/build-a-${str}`
);
cy.get('#dynamic-front-end-form')
.get('#solution')
.type('https://codepen.io/camperbot/full/oNvPqqo', {
force: true
});
cy.contains("I've completed this challenge").click();
cy.contains('Submit and go to next challenge').click();
};
projects.forEach(project => submitProject(project));
});
it('Should have a pop up modal', () => {
cy.contains(
'Nicely done. You just completed Responsive Web Design Projects.'
);
});
});

View File

@ -0,0 +1,85 @@
/* global cy expect */
const selectors = {
challengeMap: "[data-test-label='learn-curriculum-map']"
};
const locations = {
index: '/learn'
};
const superBlockNames = [
'Responsive Web Design Certification',
'JavaScript Algorithms and Data Structures Certification',
'Front End Development Libraries Certification',
'Data Visualization Certification',
'APIs and Microservices Certification',
'Quality Assurance Certification',
'Scientific Computing with Python Certification',
'Data Analysis with Python Certification',
'Information Security Certification',
'Machine Learning with Python Certification',
'Coding Interview Prep (Thousands of hours of challenges)'
];
describe('Learn Landing page (not logged in)', () => {
it('Should render', () => {
cy.visit(locations.index);
cy.title().should(
'eq',
'Learn to Code — For Free — Coding Courses for Busy People'
);
});
it('Has the correct heading for an unauthenticated User', () => {
cy.visit(locations.index);
cy.contains('h1', "Welcome to freeCodeCamp's curriculum.");
});
it('Should render a curriculum map', () => {
cy.document().then(document => {
const superBlocks = document.querySelectorAll(
`${selectors.challengeMap} > li > a`
);
expect(superBlocks).to.have.length(11);
superBlocks.forEach((superBlock, idx) => {
expect(superBlock.innerText).to.have.string(superBlockNames[idx]);
});
});
});
});
describe('Quotes', () => {
beforeEach(() => {
cy.visit('/');
cy.contains("Get started (it's free)").click();
});
it('Should show a quote', () => {
cy.get('blockquote').within(() => {
cy.get('q').should('be.visible');
});
});
it('Should show quote author', () => {
cy.get('blockquote').within(() => {
cy.get('cite').should('be.visible');
});
});
});
describe('Superblocks and Blocks', () => {
beforeEach(() => {
cy.visit('/');
cy.contains("Get started (it's free)").click();
});
it('Has all superblocks visible', () => {
cy.wrap(superBlockNames.slice(1)).each(name => {
cy.contains(name).should('be.visible');
});
});
});

View File

@ -0,0 +1,54 @@
/* global cy expect */
const locations = {
chalSuper: '/challenges/responsive-web-design/',
chalBlock: '/challenges/responsive-web-design/basic-html-and-html5',
chalChallenge:
// eslint-disable-next-line max-len
'/challenges/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements',
learnSuper: '/learn/responsive-web-design',
learnBlock: '/learn/responsive-web-design/basic-html-and-html5',
learnChallenge:
// eslint-disable-next-line max-len
'/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements'
};
describe('challenges/superblock redirect', function () {
it('redirects to learn/superblock', () => {
cy.visit(locations.chalSuper);
cy.title().should(
'eq',
'Responsive Web Design Certification | freeCodeCamp.org'
);
cy.location().should(loc => {
expect(loc.pathname).to.eq(locations.learnSuper);
});
});
});
describe('challenges/superblock/block redirect', function () {
it('redirects to learn/superblock/block', () => {
cy.visit(locations.chalBlock);
cy.title().should('eq', 'Basic HTML and HTML5 | freeCodeCamp.org');
cy.location().should(loc => {
expect(loc.pathname).to.eq(locations.learnBlock);
});
});
});
describe('challenges/superblock/block/challenge redirect', function () {
it('redirects to learn/superblock/block/challenge', () => {
cy.visit(locations.chalChallenge);
cy.title().should(
'eq',
// eslint-disable-next-line max-len
'Learn Basic HTML and HTML5: Say Hello to HTML Elements | freeCodeCamp.org'
);
cy.location().should(loc => {
expect(loc.pathname).to.eq(locations.learnChallenge);
});
});
});

View File

@ -0,0 +1,81 @@
/* global cy */
const selectors = {
tableOfContents: '.intro-toc',
warningMessage: '.flash-message-enter-active'
};
const locations = {
index: '/learn/responsive-web-design/basic-css/'
};
const lessonNames = [
'Change the Color of Text',
'Use CSS Selectors to Style Elements',
'Use a CSS Class to Style an Element',
'Style Multiple Elements with a CSS Class',
'Change the Font Size of an Element',
'Set the Font Family of an Element',
'Import a Google Font',
'Specify How Fonts Should Degrade',
'Size Your Images',
'Add Borders Around Your Elements',
'Add Rounded Corners with border-radius',
'Make Circular Images with a border-radius',
'Give a Background Color to a div Element',
'Set the id of an Element',
'Use an id Attribute to Style an Element',
'Adjust the Padding of an Element',
'Adjust the Margin of an Element',
'Add a Negative Margin to an Element',
'Add Different Padding to Each Side of an Element',
'Add Different Margins to Each Side of an Element',
'Use Clockwise Notation to Specify the Padding of an Element',
'Use Clockwise Notation to Specify the Margin of an Element',
'Use Attribute Selectors to Style Elements',
'Understand Absolute versus Relative Units',
'Style the HTML Body Element',
'Inherit Styles from the Body Element',
'Prioritize One Style Over Another',
'Override Styles in Subsequent CSS',
'Override Class Declarations by Styling ID Attributes',
'Override Class Declarations with Inline Styles',
'Override All Other Styles by using Important',
'Use Hex Code for Specific Colors',
'Use Hex Code to Mix Colors',
'Use Abbreviated Hex Code',
'Use RGB values to Color Elements',
'Use RGB to Mix Colors',
'Use CSS Variables to change several elements at once',
'Create a custom CSS Variable',
'Use a custom CSS Variable',
'Attach a Fallback value to a CSS Variable',
'Improve Compatibility with Browser Fallbacks',
'Inherit CSS Variables',
'Change a variable for a specific area',
'Use a media query to change a variable'
];
const warningMessage =
'Note: Some browser extensions may interfere with elements on the page. ' +
'If the tests fail, try disabling your extensions for the most reliable ' +
'experience.';
describe('Basic Css Introduction page', function () {
it('renders', () => {
cy.visit(locations.index);
cy.title().should('eq', 'Basic CSS | freeCodeCamp.org');
});
it('renders a warning user about extensions', () => {
cy.visit(locations.index);
cy.get(selectors.warningMessage).contains(warningMessage);
});
it('renders a lesson index', () => {
lessonNames.forEach(name => {
cy.get(selectors.tableOfContents).contains('span', name);
});
});
});

View File

@ -0,0 +1,41 @@
/* global cy */
const selectors = {
firstBlock: '.block-ui > .block:nth-child(1) > .map-title'
};
describe('Certification intro page', () => {
before(() => {
cy.clearCookies();
cy.login();
cy.visit('/learn/responsive-web-design');
});
it('Should render', () => {
cy.title().should(
'eq',
'Responsive Web Design Certification | freeCodeCamp.org'
);
});
it('Should have certification intro text', () => {
cy.contains(
"In this Responsive Web Design Certification, you'll learn the languages that developers use to build webpages"
).should('be.visible');
});
it('First block should be expanded', () => {
cy.contains('Say Hello to HTML Elements').should('be.visible');
});
it('Second block should be closed', () => {
cy.contains('Change the Color of Text').should('not.exist');
});
it('Block should handle toggle clicks correctly', () => {
cy.get(selectors.firstBlock).click();
cy.contains('Say Hello to HTML Elements').should('not.exist');
cy.get(selectors.firstBlock).click();
cy.contains('Say Hello to HTML Elements').should('be.visible');
});
});