UNPKG

12.1 kBMarkdownView Raw
1# POM CukeTractor - Cucumber Protractor Runner with Setup for Page Object Model
2
3[![Build Status](https://travis-ci.org/canvaspixels/cucumber-protractor.svg?branch=master)](https://travis-ci.org/canvaspixels/cucumber-protractor)
4
5![POM Cuke Tractor](https://raw.githubusercontent.com/canvaspixels/cucumber-protractor/master/pomCukeTractor.png)
6
7## Create easy-to-read, functioning scenarios in seconds:
8
9### Setup
10
11This assumes that you have an npm project. If you don't then make a new one with `npm init`. It also assumes you are on a Mac or Windows and have node 8+, npm 6+, and the latest version of Chrome installed.
12
131. Install the package: type `npm install cucumber-protractor` into your terminal
142. Copy: `node node_modules/cucumber-protractor/scripts/setup.js` into your terminal. This will create a `uiTests` folder with the sample in it, a sample config and add the `ct` script to your package.json. Note it's `node node_modules\cucumber-protractor\scripts\setup.js` on Windows.
153. Run the sample, type `npm run ct` into your terminal.
16
17### Futher tips:
18
191. To improve organisation and scalability, easily compose Page Objects and Component Objects. Page Objects and Component Objects are composed of [Locators](https://www.protractortest.org/#/locators), custom methods, and other Component Objects. Components can compose Components which compose Components etc. The only difference between a Page Object and a Component Object is a Component Object does not have an URL. Use the [step definitions provided](https://github.com/canvaspixels/cucumber-protractor/blob/master/STEP_DEFINITIONS.md#step-definitions) (or create your own) to write your own first scenario.
202. If you're using source control such as git, add `uiTestResult` to your .gitignore file
213. As an improvement, to suppress deprecation warnings (if running node > 8) and also to type `cuketractor` or `ct` rather than typing `npm run ct` each time, you can add the following lines to your `~/.bash_profile` file:
22
23```
24alias cuketractor="PATH=$(npm bin):$PATH NODE_OPTIONS=--no-deprecation cuketractor"
25alias ct="PATH=$(npm bin):$PATH NODE_OPTIONS=--no-deprecation cuketractor"
26```
27
28This is the same command that was added to your package.json. This means you don't have to put npm run each time.
29
30## Feature file by example
31
32```gherkin
33@google-home
34Feature: Test feature
35
36 @google-home-feeling-lucky
37 Scenario: I am testing this out
38 Given I am on the 'Google Home' page
39 When I click 'I’m Feeling Lucky'
40 Then I expect the url to contain 'google.com'
41```
42
43All you need to be able to run the scenario above is a page object that looks like this inside a kebab-case yaml file e.g. `google-home.page`, placed in the `uiTests/pages` folder:
44
45```yaml
46path: https://www.google.com/
47
48selectors:
49 I’m Feeling Lucky: [value="I'm Feeling Lucky"]
50```
51
52...or if you want the boilerplate js code and need more flexibility place the following in `google-home.js` in the same folder (again kebab-case is important):
53
54```js
55const createPage = require('cucumber-protractor/uiTestHelpers/createPage');
56const fileName = createPage.getFileName(__filename);
57
58module.exports = (world) => {
59 const pagePath = 'https://www.google.com/';
60 const locators = {
61 'I’m Feeling Lucky': by.css('[value="I\'m Feeling Lucky"]'),
62 };
63
64 return createPage(fileName, world, pagePath, locators);
65};
66```
67
68Note that a `.page` file will take precedence over a `.js` page object file.
69
70You don't need to write any page object methods, nor step definitions. How easy is that!!?
71
72It's important that the page object name is kebab-case and lowercase. E.g. `about-us.js` or `about-something-else.js` or `google-home.js` as in the sample. `Given I am on the 'Google Home' page` sets the current page object and `Google Home` gets translated behind the scenes to `google-home.js` so make sure `Google Home` has the space in it.
73
74It’s advisable when writing your features to add a tag at the top of the Feature file and a tag to the beginning of each Scenario. A tag starts with a @. As a convention you can prefix each Scenario tag with whatever you've used at the top of the file (in this case @google-home). Try and keep them unique for your ease of use.
75
76Note you can add more than one tag to each scenario and you could tag them when a hook tag that you can hook into Before or After each scenario. [Read more about hooks](https://github.com/cucumber/cucumber-js/blob/master/docs/support_files/hooks.md) just add hooks to the existing ones in your conf.js file.
77
78```gherkin
79@google-home
80Feature: Test feature
81
82 @google-home-feeling-lucky
83 Scenario: ...
84 Given ...
85 When ...
86 Then ...
87
88 @google-home-another-thing @some-special-hook-before-each-run
89 Scenario: ...
90 Given ...
91 When ...
92 Then ...
93
94 @google-home-yet-another-thing @some-special-hook-before-each-run
95 Scenario: ...
96 Given ...
97 When ...
98 Then ...
99```
100
101## Running just one feature or one scenario
102
103Continuing on from the examples above...
104
105To run just one feature:
106
107```console
108npm run ct --tags=@google-home
109
110OR SIMPLY JUST
111
112npm run ct @google-home
113```
114
115To run just one scenario:
116
117```console
118npm run ct --tags=@google-home-another-thing
119
120OR SIMPLY JUST
121
122npm run ct @google-home-another-thing
123```
124
125To run a couple (comma separate):
126
127```console
128npm run ct --tags=@google-home-feeling-lucky,@google-home-another-thing
129
130OR SIMPLY JUST
131
132npm run ct @google-home-feeling-lucky,@google-home-another-thing
133```
134
135## Viewing your test run
136
137If you get an error, you'll see a screenshot for each step error inside the `uiTestResult` folder and a link to each one from the console output in your terminal. However, if you want to view the browser running each step, you can put disableHeadless=true before the cuketractor command like this:
138
139```console
140disableHeadless=true npm run ct
141```
142
143That'll launch Chrome by default and you'll be able to see your tests run.
144
145## conf.js file
146
147The conf file allows you to specify the following:
148
149* folder locations for the following
150 - test results
151 - page objects
152 - component objects
153 - feature files
154 - hooks
155* step timeoutInSeconds - how long a step will wait to complete before it times out
156* baseUrl - the hostname will prefix the paths you set in your page objects
157* capabilities for different browsers, Chrome is the default. You can point to services like browserstack or saucelabs to test a matrix of platforms and browsers
158
159To point to a different configuration file:
160
161```console
162npm run ct --confFile=staging.conf.js
163```
164
165## .page files and .component files
166
167### .page file example
168
169Example of a page object located at `uiTests/pages/simple.page`:
170
171```yaml
172path: /simple-page
173
174selectors:
175 Go to home page by react router link: [data-test="go-to-home-link"]
176 some other element selected by class: .my-class
177 some other element selected by id: '#my-class'
178
179XPaths:
180 main heading: //*[contains(@class, "main-heading")]
181 another element: //*[contains(@class, "something-else")]
182
183components:
184 - banner
185 - footer
186```
187
188A .page file is made up of:
189
190* path - the page's path, navigated to when you use the `Given I am on the 'simple' page` step
191* selectors - css selectors, the name on the left side of the : is what you put in your gherkin steps, the selector on the right references your html element. Note if you use id selectors (with a hash) you need to put it in quotes '' or the yaml file will think it's a comment
192* XPaths - same as selectors but using XPath selectors instead
193* components - a list of components which will be loaded in from the `uiTests/components` folder and composed into the page object (see .component file example of the footer component)
194
195
196### .component file example
197
198Example of a component object located at `uiTests/components/footer.component`:
199
200```yaml
201selectors:
202 footer wrapper: .footer
203
204components:
205 - footer-item1
206 - footer-item2
207```
208
209A .component file is made up of:
210
211* selectors - css selectors, the name on the left side of the : is what you put in your gherkin steps, the selector on the right references your html element. Note if you use id selectors (with a hash) you need to put it in quotes '' or the yaml file will think it's a comment
212* XPaths - same as selectors but using XPath selectors instead
213* components - a list of components which will be loaded in from the `uiTests/components` folder and composed into the component object
214
215
216## Snippets
217
218Snippets are available for Sublime Text 3, Webstorm (live templates), VSCode and Atom. To add them to your editor do the following.
219
220For Sublime Text 3:
221
222```console
223node node_modules/cucumber-protractor/scripts/generateSnippetsSublime.js --genFiles --justForIDE
224```
225
226For Atom:
227
228```console
229node node_modules/cucumber-protractor/scripts/generateSnippetsAtom.js --genFiles --justForIDE
230```
231
232For VSCode:
233
234```console
235node node_modules/cucumber-protractor/scripts/generateSnippetsVSCode.js --genFiles --justForIDE
236```
237
238For Webstorm:
239
240```console
241node node_modules/cucumber-protractor/scripts/generateSnippetsWebstorm.js --genFiles --justForIDE
242```
243
244For IntelliJ:
245
246```console
247node node_modules/cucumber-protractor/scripts/generateSnippetsIntelliJ.js --genFiles --justForIDE
248```
249
250You may need to restart after running the commands for the JetBrains IDEs.
251
252## Combining steps
253
254While the gherkin step examples in this repo are all single actions and assertions, you can easily combine a number of steps into one.
255
256For example in a scenario that has the following steps:
257
258```gherkin
259Scenario: I expect to see items in the dashboard menu
260 Given I am on the 'twitter login' page
261 When I set 'username' to 'peoplesvote_uk'
262 And I set 'password' to 'password~1'
263 And I submit the 'login form'
264 Then I expect to be on the 'dashboard' page
265 When I click the 'dashboard menu'
266 Then I expect the 'dashboard menu items' to be visible
267```
268
269we could simplify it by combining them into one so that it is more obvious what we are intending to test:
270
271```gherkin
272Scenario: I expect to see items in the dashboard menu
273 Given I am logged in
274 When I click the 'dashboard menu'
275 Then I expect the 'dashboard menu items' to be visible
276```
277
278This allows you to stop repeating yourself with the login steps, making them more reusable. Also it makes the test much more readable and focusses on the subject in test. It is a precondition that we need to be logged in and not really what we are testing. If you are in control of your mocks and are able to mock out a logged-in state, say with cookies, then that is preferable as it'll take a lot less time to run. But if you are doing system tests on a staging environment for example then you may have to login how a user would do, via the login form. Remember to keep your credentials out of your repository!
279
280To add a `Given I am logged in` step we’ll need to create our own custom step definition. Add this to the bottom of `uiTests/stepDefinitions/common-step-defintions.js` and change the username and password twitter credentials:
281
282```js
283Given(/^I am logged in$/, async function() {
284 await this.goToPage('twitter login');
285 await this.setInputFieldValue('username', 'peoplesvote_uk');
286 await this.setInputFieldValue('password', 'password~1');
287 await this.submitForm('login form');
288 await this.checkUrlIs('https://twitter.com');
289});
290```
291
292Create yourself a new feature file, let's call it `twitter-dashboard-menu.feature` and save it in the `uiTests/features` folder. Paste the following into it:
293
294```gherkin
295@twitter-dashboard-menu
296Feature: Test feature
297
298 @twitter-dashboard-menu-items
299 Scenario: I expect to see items in the dashboard menu
300 Given I am logged in
301```
302
303Then run that scenario: `npm run ct @twitter-dashboard-menu-items`
304
305Have a look at the [available methods](https://github.com/canvaspixels/cucumber-protractor/blob/master/METHODS_FOR_COMBINING.md#methods-for-combining-actions-and-assertions) that you can use to combine your steps.
306
307## Contributing
308
309Please get in touch if you'd like to contribute to this project.
310
311To create the STEP_DEFINITIONS.md and snippets files, run the script: `npm run build-readme-and-snippets`
\No newline at end of file