-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
migration - chapter08 (testing-angular-applications#1)
Previous commit messages from chapter-8-code: * test(simple): write first test to find the contact list title (testing-angular-applications#1) - Set up repo similar to the angular-cli e2e directory structure. Protractor.conf.js, tsconf.json, and tslint.json match the angular-cli files. - Update dependencies and devDependencies to run Protractor test. - Add scripts to package.json to transpile typescript files, download chromedriver binary, and run the protractor test. - Use a page object called contact-list.po. - Write a test using the page object. the test verifies that the title is not null and matches the title. * test(simple): create a protractor config for the simple test (testing-angular-applications#2) - use the protractor.conf.js as the base configuration - edit the specs array to run only the first test * test(first-test): create a barebones test (testing-angular-applications#3) The first test is runnable with `npm run e2e test-8-0.conf.js`. Running the first test command should launch the `pree2e` command. This will launch webdriver-manager to download the chromedriver binary. Protractor will then run the `e2e/test-8-0.e2e-spec.ts` file and navigate to https://angularjs.org and check to see if the current url matches. * test(8.1): example for section 8.1 (testing-angular-applications#4) * test(8.2): example for section 8.2 (testing-angular-applications#5) Test adding a new contact by: - clicking the add button - filling out the contact form - clicking the submit button Covers: - finding elements with by.id and by.buttonText - interacting with elements by clicking and sending keys - browser alerts and dismissing them - waiting for expected conditions * try(circleci): add circleci 2.0 (testing-angular-applications#9) Use circleci 2.0 with directConnect. This does not take advantage of docker-compose but this is a good starting point. * test(8.1 and 8.2): update for jenkins (testing-angular-applications#12) * test(element): a collection of element methods (testing-angular-applications#13) * test(tables): examples for `by` and `element` methods (testing-angular-applications#14) * test(element.all): examples to filter, map, and reduce (testing-angular-applications#15) * test(pageobjects): add page objects to test-8-4 (testing-angular-applications#16) * fix package.json details (testing-angular-applications#17) * update readme to include circle ci build shield (testing-angular-applications#18) * improve tables to have more examples and comments (testing-angular-applications#19) * change the alert message dismiss to modal click (testing-angular-applications#20) * after dismissing the modal, use expected conditions to check that it is not there (testing-angular-applications#21) * fix tests for ElementArrayFinder and TypeScript errors (testing-angular-applications#22) * rename files to more meaningful names. (testing-angular-applications#23) - rename *.e2e-spec.ts files to more meaningful names - rename protractor configuration files to more meaningful names - add clang formatting and format everything - update circleci to run all test suites and enforce formatting * add linter checks (testing-angular-applications#25) * separate out add contact into two files and use globbing in conf (testing-angular-applications#26) * remove extra describes from the add contact tests (testing-angular-applications#27) * clean up page objects (testing-angular-applications#28) * use onPrepare method over beforeLaunch (testing-angular-applications#29) * migration - move chapter 8 code to chapter08/
- Loading branch information
Showing
26 changed files
with
1,021 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
version: 2 | ||
jobs: | ||
build: | ||
working_directory: ~/workspace | ||
docker: | ||
- image: circleci/node:7-browsers | ||
steps: | ||
- checkout | ||
|
||
- run: node --version | ||
- run: npm --version | ||
- run: java -version | ||
- run: google-chrome --version | ||
- run: yarn --version | ||
|
||
- run: yarn install | ||
- run: yarn run format-enforce | ||
- run: yarn run lint | ||
|
||
# Individual tests | ||
- run: xvfb-run -a yarn run e2e protractor-first-test.conf.js | ||
- run: xvfb-run -a yarn run e2e protractor-add-contact.conf.js | ||
- run: xvfb-run -a yarn run e2e protractor-invalid-contact.conf.js | ||
- run: xvfb-run -a yarn run e2e protractor-contact-list.conf.js | ||
- run: xvfb-run -a yarn run e2e protractor-page-objects.conf.js | ||
- run: xvfb-run -a yarn run e2e protractor-tables.conf.js | ||
|
||
# Run all tests | ||
- run: xvfb-run -a yarn run e2e protractor.conf.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Language: JavaScript | ||
BasedOnStyle: Google | ||
ColumnLimit: 80 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# See http://help.github.com/ignore-files/ for more about ignoring files. | ||
|
||
# compiled output | ||
/dist | ||
/tmp | ||
|
||
# dependencies | ||
/node_modules | ||
/bower_components | ||
|
||
# IDEs and editors | ||
/.idea | ||
|
||
# misc | ||
/.vscode | ||
/.sass-cache | ||
/connect.lock | ||
/coverage/* | ||
/libpeerconnection.log | ||
npm-debug.log | ||
testem.log | ||
/typings | ||
|
||
# e2e | ||
/e2e/*.js | ||
/e2e/*.map | ||
|
||
# unit tests | ||
*.spec.ts | ||
|
||
#System Files | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Chapter 8 [![CircleCI Status](https://circleci.com/gh/testing-angular-applications/chapter-8-code.svg?style=shield)](https://circleci.com/gh/testing-angular-applications/chapter-8-code) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import {browser, by, element, ExpectedConditions as EC} from 'protractor'; | ||
|
||
describe('adding a new contact with only a name', () => { | ||
beforeAll(() => { | ||
browser.get('/'); | ||
}); | ||
|
||
it('should find the add contact button', () => { | ||
element(by.id('add-contact')).click(); | ||
expect(browser.getCurrentUrl()).toEqual(browser.baseUrl + '/add'); | ||
}); | ||
|
||
it('should write a name', () => { | ||
element(by.id('contact-name')).sendKeys('Ada'); | ||
expect(element(by.id('contact-name')).getAttribute('value')).toEqual('Ada'); | ||
}); | ||
|
||
it('should click the create button', () => { | ||
element(by.css('.create-button')).click(); | ||
expect(browser.getCurrentUrl()).toEqual(browser.baseUrl + '/'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import {browser, by, element, ExpectedConditions as EC} from 'protractor'; | ||
|
||
describe('adding a new contact with name, email, and phone number', () => { | ||
beforeAll(() => { | ||
browser.get('/'); | ||
element(by.id('add-contact')).click(); | ||
element(by.id('contact-name')).sendKeys('Grace\'s Directive'); | ||
}); | ||
|
||
it('should send an email address', () => { | ||
let email = element(by.id('contact-email')); | ||
email.sendKeys('grace@example.com'); | ||
expect(email.getAttribute('value')).toEqual('grace@example.com'); | ||
}); | ||
|
||
it('should send a phone number', () => { | ||
let tel = element(by.css('input[type="tel"]')); | ||
tel.sendKeys('1234567890'); | ||
expect(tel.getAttribute('value')).toEqual('1234567890'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import {browser, by, element, ElementFinder} from 'protractor'; | ||
import {promise as wdpromise} from 'selenium-webdriver'; | ||
|
||
export interface Contact { | ||
name?: string; | ||
email?: string; | ||
tel?: string; | ||
} | ||
|
||
describe('the contact list', () => { | ||
beforeAll(() => { | ||
browser.get('/'); | ||
}); | ||
|
||
it('with filter: should find existing contact "Craig Service"', () => { | ||
let tbody = element(by.tagName('tbody')); | ||
let trs = tbody.all(by.tagName('tr')); | ||
let craigService = trs.filter(elem => { | ||
// The tds: 0 = mood, 1 = name, 2 = email, 3 = phone number | ||
return elem.all(by.tagName('td')).get(1).getText().then(text => { | ||
return text === 'Craig Service'; | ||
}); | ||
}); | ||
// Nothing happens here until you use it. Although we called getText in the | ||
// filter function, it is not executed until we use it. When you use it, the | ||
// promises enter the control flow and are resolved. This is similar to | ||
// calling element(), nothing happens until you do something like getText(). | ||
expect(craigService.count()).toBeGreaterThan(0); | ||
expect(craigService.all(by.tagName('td')).get(2).getText()) | ||
.toEqual('craig.services@example.com'); | ||
}); | ||
|
||
let expectedContactList: Contact[] = [ | ||
{ | ||
name: 'Adrian Directive', | ||
email: 'adrian.directive@example.com', | ||
tel: '+1 (703) 555-0123' | ||
}, | ||
{ | ||
name: 'Rusty Component', | ||
email: 'rusty.component@example.com', | ||
tel: '+1 (441) 555-0122' | ||
}, | ||
{ | ||
name: 'Jeff Pipe', | ||
email: 'jeff.pipe@example.com', | ||
tel: '+1 (714) 555-0111' | ||
}, | ||
{ | ||
name: 'Craig Service', | ||
email: 'craig.services@example.com', | ||
tel: '+1 (514) 555-0132' | ||
} | ||
]; | ||
|
||
it('with map: should create a map object', () => { | ||
let tbody = element(by.tagName('tbody')); | ||
let trs = tbody.all(by.tagName('tr')); | ||
let contactList = trs.map(elem => { | ||
let contact: Contact = {}; | ||
let tds = elem.all(by.tagName('td')); | ||
// We need to get the values of the contact name and email. Since these | ||
// are in a couple of different promises, we'll create a promise array. | ||
let promises: any[] = []; | ||
|
||
// Getting the text returns a promise of a string then the next function | ||
// sets the contact's name. This function returns void so the final | ||
// promise saved is of Promise<void>. We set the promise array to be of | ||
// type any since we do not care about the promise type. | ||
promises.push(tds.get(1).getText().then(text => { | ||
contact.name = text; | ||
})); | ||
promises.push(tds.get(2).getText().then(text => { | ||
contact.email = text; | ||
})); | ||
promises.push(tds.get(3).getText().then(text => { | ||
contact.tel = text; | ||
})); | ||
|
||
// Resolve all the promises and return the contact. | ||
return Promise.all(promises).then(() => { | ||
return contact; | ||
}); | ||
}) | ||
|
||
// Check the results | ||
expect(contactList).toBeDefined(); | ||
contactList.then((contacts: Contact[]) => { | ||
|
||
// Spot check the results | ||
expect(contacts.length).toEqual(4); | ||
expect(contacts[0]).toBeDefined(); | ||
expect(contacts[1].email).toEqual('rusty.component@example.com'); | ||
expect(contacts[2].tel).toEqual('+1 (714) 555-0111'); | ||
expect(contacts[3].name).toEqual('Craig Service'); | ||
|
||
// Check all the contacts match | ||
expect(contacts).toEqual(expectedContactList); | ||
}); | ||
}); | ||
|
||
it('with reduce: get a list of contact names', () => { | ||
let tbody = element(by.tagName('tbody')); | ||
let trs = tbody.all(by.tagName('tr')); | ||
let contacts = trs.reduce((acc, curr) => { | ||
let name = curr.all(by.tagName('td')).get(1); | ||
return name.getText().then(text => { | ||
return acc === '' ? text : acc + ', ' + text; | ||
}); | ||
}, ''); | ||
|
||
expect(contacts).toBe( | ||
'Adrian Directive, Rusty Component, Jeff Pipe, Craig Service'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import {browser} from 'protractor'; | ||
|
||
// Listing 8.4 | ||
describe('our first Protractor test', () => { | ||
it('should load a page and verify the url', () => { | ||
browser.get('/'); | ||
expect(browser.getCurrentUrl()).toEqual(browser.baseUrl + '/'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import {browser, by, element, ExpectedConditions as EC} from 'protractor'; | ||
|
||
describe('adding a new contact', () => { | ||
describe('with an invalid email', () => { | ||
beforeEach(() => { | ||
browser.get('/add'); | ||
element(by.id('contact-name')).sendKeys('Bad Email'); | ||
}); | ||
|
||
it('should not create a new contact with baduser.com', () => { | ||
let email = element(by.id('contact-email')); | ||
email.sendKeys('baduser.com'); | ||
element(by.buttonText('Create')).click(); | ||
|
||
let invalidEmailModal = element(by.tagName('app-invalid-email-modal')); | ||
expect(invalidEmailModal.isPresent()).toBe(true); | ||
|
||
let modalButton = invalidEmailModal.element(by.tagName('button')); | ||
modalButton.click(); | ||
|
||
browser.wait(EC.not(EC.presenceOf(invalidEmailModal)), 5000); | ||
expect(invalidEmailModal.isPresent()).toBe(false); | ||
expect(browser.getCurrentUrl()).toEqual(browser.baseUrl + '/add'); | ||
}); | ||
|
||
it('should not create a new contact with @baduser.com', () => { | ||
let email = element(by.id('contact-email')); | ||
email.sendKeys('@baduser.com'); | ||
let invalidEmailModal = element(by.tagName('app-invalid-email-modal')); | ||
expect(invalidEmailModal.isPresent()).toBe(false); | ||
}); | ||
}); | ||
|
||
describe('with an invalid phone number', () => { | ||
beforeEach(() => { | ||
browser.get('/add'); | ||
element(by.id('contact-name')).sendKeys('Bad Tel'); | ||
}); | ||
|
||
it('should not create a new contact with a formatted telephone number', | ||
() => { | ||
let tel = element(by.css('input[type="tel"]')); | ||
tel.sendKeys('123-456-7890'); | ||
element(by.buttonText('Create')).click(); | ||
let invalidTelModal = | ||
element(by.tagName('app-invalid-phone-number-modal')); | ||
expect(invalidTelModal.isDisplayed()).toBe(true); | ||
let modalButton = invalidTelModal.element(by.tagName('button')); | ||
modalButton.click(); | ||
|
||
browser.wait(EC.not(EC.presenceOf(invalidTelModal)), 5000); | ||
expect(invalidTelModal.isPresent()).toBe(false); | ||
expect(browser.getCurrentUrl()).toEqual(browser.baseUrl + '/add'); | ||
}); | ||
|
||
it('should not create a new contact with too many numbers in the telephone number', | ||
() => { | ||
let tel = element(by.css('input[type="tel"]')); | ||
tel.sendKeys('12345678901'); | ||
element(by.buttonText('Create')).click(); | ||
let invalidTelModal = | ||
element(by.tagName('app-invalid-phone-number-modal')); | ||
expect(invalidTelModal.isDisplayed()).toBe(true); | ||
let modalButton = invalidTelModal.element(by.tagName('button')); | ||
modalButton.click(); | ||
|
||
browser.wait(EC.not(EC.presenceOf(invalidTelModal)), 5000); | ||
expect(invalidTelModal.isPresent()).toBe(false); | ||
expect(browser.getCurrentUrl()).toEqual(browser.baseUrl + '/add'); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import {browser, by} from 'protractor'; | ||
|
||
import {COL, Contact, ContactListPageObject, NewContactPageObject} from './po'; | ||
|
||
describe('contact list', () => { | ||
let contactList: ContactListPageObject; | ||
let newContact: NewContactPageObject; | ||
|
||
beforeAll(() => { | ||
// We could also add the browser object here. For example: new | ||
// ContactListPO(browser). This could become important if we fork the | ||
// browser since the browser object refers to the current selenium session. | ||
contactList = new ContactListPageObject(); | ||
}); | ||
|
||
describe('add a new contact', () => { | ||
beforeAll(() => { | ||
contactList.navigateTo(); | ||
}); | ||
|
||
it('should click the + button', () => { | ||
newContact = contactList.clickPlusButton(); | ||
expect(newContact.getCurrentUrl()).toBe(browser.baseUrl + '/add'); | ||
}); | ||
|
||
it('should fill out form for a new contact', () => { | ||
newContact.setContactInfo('Mr. Newton', 'mr.newton@example.com', null); | ||
expect(newContact.getName()).toBe('Mr. Newton'); | ||
expect(newContact.getEmail()).toBe('mr.newton@example.com'); | ||
expect(newContact.getPhone()).toBe(''); | ||
}); | ||
|
||
it('should click the create button', () => { | ||
contactList = newContact.clickCreateButton(); | ||
expect(contactList.getCurrentUrl()).toBe(browser.baseUrl + '/'); | ||
}); | ||
}); | ||
|
||
describe('read contact list', () => { | ||
it('should find the new contact', () => { | ||
let tableRow = contactList.findContact('Mr. Newton').get(0); | ||
let tableData = tableRow.all(by.tagName('td')); | ||
expect(tableData.get(COL.name).getText()).toBe('Mr. Newton'); | ||
expect(tableData.get(COL.email).getText()).toBe('mr.newton@example.com'); | ||
expect(tableData.get(COL.phoneNumber).getText()).toBe(''); | ||
}); | ||
|
||
it('should find the contacts and verify each value', () => { | ||
let contacts = contactList.getContacts(); | ||
contacts.then((contacts: Contact[]) => { | ||
expect(contacts.length).toBe(5); | ||
expect(contacts[0]).toBeDefined(); | ||
expect(contacts[1].email).toBe('rusty.component@example.com'); | ||
expect(contacts[2].tel).toBe('+1 (714) 555-0111'); | ||
expect(contacts[3].name).toBe('Craig Service'); | ||
expect(contacts[4].name).toBe('Mr. Newton'); | ||
}); | ||
}); | ||
|
||
it('should get the contact names so we can print them to console', () => { | ||
let contactNames = contactList.getContactNames(); | ||
let expectedNames = | ||
'Adrian Directive, Rusty Component, Jeff Pipe, Craig Service, Mr. Newton'; | ||
expect(contactNames).toBe(expectedNames); | ||
contactNames.then(text => { | ||
console.log(text); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.