-
Notifications
You must be signed in to change notification settings - Fork 1
End to End Testing (E2E)
End-to-end testing is how we can test actual user behavior on the frontend. Using an automated browser driver, we can write code to simulate user actions like clicking buttons, filling out forms, and scrolling around a page. At the same time, we can hook into the browser's display behavior and test for various conditions like whether an element is disabled and the text inside elements.
Lucky for us, Angular comes with an E2E testing framework called Protractor (see what they did there?).
It's important to make sure every component of a project is functional when making changes to code. For example, you could have a perfectly secure, accurate, and performant backend, but if your frontend can't properly interact with it, then you'll still have problems. There's nothing wrong with testing these manually, but it can become quite a pain, especially when you're trying to check a specific edge case. Frameworks like Protractor make it easy to do automatically.
From the root directory, run npm run e2e
or ng e2e
.
- Make sure you have Chrome or Firefox installed, depending on what the current Protractor config (
e2e/protractor.conf.js
) says. - If Protractor yells at you for not having the right driver installed, try
npx webdriver-manager update
. - Try removing your
node_modules
folder and reinstalling withnpm install -D
. - Google is your friend! Protractor is notorious for sometimes having cryptic errors, so make sure to look them up and try whatever you can find.
When writing tests for a page, there's two components to be aware of: the page object and the spec file.
Page objects go inside the e2e/page-objects
folder and are named {page}.po.ts
by convention. Each page object file contains a class dedicated to the page containing relevant methods and accessors to make specs cleaner and easier to write. All page objects should have a navigateTo()
method that takes the browser to that page.
export class SomethingPage {
async navigateTo() {
await browser.get('/something');
}
get somethingButton() {
return element(by.buttonText('Do Something'));
}
get somethingTextBox() {
return element(by.css('.my-text-box'));
}
async somethingComplex(exampleParameter: string) {
// do something complex that's commonly needed in specs
// don't write a whole method just to click a button!
}
}
For more examples, see existing page objects.
Spec files contain the test suite for each page. These are in the e2e
directory and must be named {page}.e2e-spec.ts
for Protractor to find them.
Each suite consists of a describe
block and at least one it
block. A describe
block creates a new scope, which is mainly used to designate features or different scenarios within a feature. it
blocks define tests to run. There are also several different kinds of lifecycle hooks available, such as beforeEach
, afterEach
, beforeAll
, and afterAll
. Take a look at the Jasmine documentation for details. Note that these functions do not need to be explicitly imported.
Assertions are done with the expect
function, which has several different matchers available on it. Some common ones are .toBe()
, .toBeTruthy()
, and .toBeNull()
, to name a few. The Jasmine API docs has a list of all the available ones.
describe('Something', () => {
let page: SomethingPage;
beforeAll(() => {
page = new SomethingPage();
});
beforeEach(async () => {
await page.navigateTo();
});
it('does a thing', async () => {
await page.somethingButton.click();
expect(await page.somethingTextBox.getText()).toContain('blah blah blah');
});
describe('another scenario within Something', () => {
it('does another thing', async () => {
await page.somethingComplex();
// try to avoid hardcoding wait times, take a look at the `browser.wait` method
await browser.sleep(2500);
expect(await page.somethingTextBox.getText()).toContain('something different');
});
});
});
For more examples, see existing spec files.
If you have any issues contact support@mymicds.net.