codeceptjs 3.1.3 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +49 -1
  2. package/README.md +2 -3
  3. package/bin/codecept.js +1 -0
  4. package/docs/advanced.md +94 -60
  5. package/docs/basics.md +1 -1
  6. package/docs/build/FileSystem.js +1 -0
  7. package/docs/build/Playwright.js +19 -26
  8. package/docs/build/Protractor.js +9 -24
  9. package/docs/build/Puppeteer.js +9 -27
  10. package/docs/build/REST.js +1 -0
  11. package/docs/build/WebDriver.js +1 -23
  12. package/docs/changelog.md +49 -1
  13. package/docs/custom-helpers.md +1 -36
  14. package/docs/helpers/Appium.md +1 -1
  15. package/docs/helpers/FileSystem.md +1 -1
  16. package/docs/helpers/Playwright.md +16 -18
  17. package/docs/helpers/Puppeteer.md +1 -17
  18. package/docs/helpers/REST.md +3 -1
  19. package/docs/helpers/WebDriver.md +1 -17
  20. package/docs/mobile-react-native-locators.md +3 -0
  21. package/docs/plugins.md +125 -0
  22. package/docs/reports.md +2 -2
  23. package/lib/actor.js +19 -1
  24. package/lib/codecept.js +2 -0
  25. package/lib/command/info.js +1 -1
  26. package/lib/config.js +12 -0
  27. package/lib/container.js +3 -1
  28. package/lib/helper/FileSystem.js +1 -0
  29. package/lib/helper/Playwright.js +19 -16
  30. package/lib/helper/Protractor.js +2 -14
  31. package/lib/helper/Puppeteer.js +2 -17
  32. package/lib/helper/REST.js +1 -0
  33. package/lib/helper/WebDriver.js +1 -13
  34. package/lib/interfaces/featureConfig.js +3 -0
  35. package/lib/interfaces/scenarioConfig.js +4 -0
  36. package/lib/listener/steps.js +21 -3
  37. package/lib/listener/timeout.js +71 -0
  38. package/lib/locator.js +3 -0
  39. package/lib/plugin/allure.js +6 -1
  40. package/lib/plugin/retryTo.js +130 -0
  41. package/lib/plugin/screenshotOnFail.js +1 -0
  42. package/lib/plugin/stepByStepReport.js +7 -0
  43. package/lib/plugin/stepTimeout.js +90 -0
  44. package/lib/recorder.js +16 -5
  45. package/lib/step.js +3 -0
  46. package/lib/store.js +2 -0
  47. package/lib/ui.js +2 -2
  48. package/package.json +4 -6
  49. package/typings/index.d.ts +6 -1
  50. package/typings/types.d.ts +40 -64
  51. package/docs/angular.md +0 -325
  52. package/docs/helpers/Protractor.md +0 -1658
  53. package/docs/webapi/waitUntil.mustache +0 -11
  54. package/typings/Protractor.d.ts +0 -16
@@ -1147,7 +1147,7 @@ declare namespace CodeceptJS {
1147
1147
  * I.seeFileNameMatching('.pdf');
1148
1148
  * ```
1149
1149
  */
1150
- seeFileNameMatching(): void;
1150
+ seeFileNameMatching(text: string): void;
1151
1151
  /**
1152
1152
  * Checks that file found by `seeFile` includes a text.
1153
1153
  */
@@ -2433,6 +2433,7 @@ declare namespace CodeceptJS {
2433
2433
  * * `basicAuth`: (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
2434
2434
  * * `windowSize`: (optional) default window size. Set a dimension like `640x480`.
2435
2435
  * * `userAgent`: (optional) user-agent string.
2436
+ * * `locale`: (optional) locale string. Example: 'en-GB', 'de-DE', 'fr-FR', ...
2436
2437
  * * `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
2437
2438
  * * `chromium`: (optional) pass additional chromium options
2438
2439
  * * `electron`: (optional) pass additional electron options
@@ -2550,6 +2551,19 @@ declare namespace CodeceptJS {
2550
2551
  * }
2551
2552
  * ```
2552
2553
  *
2554
+ * #### Example #7: Launch test with a specifc user locale
2555
+ *
2556
+ * ```js
2557
+ * {
2558
+ * helpers: {
2559
+ * Playwright : {
2560
+ * url: "http://localhost",
2561
+ * locale: "fr-FR",
2562
+ * }
2563
+ * }
2564
+ * }
2565
+ * ```
2566
+ *
2553
2567
  * Note: When connecting to remote browser `show` and specific `chrome` options (e.g. `headless` or `devtools`) are ignored.
2554
2568
  *
2555
2569
  * ## Access From Helpers
@@ -3860,11 +3874,11 @@ declare namespace CodeceptJS {
3860
3874
  */
3861
3875
  waitForRequest(urlOrPredicate: string | ((...params: any[]) => any), sec?: number): void;
3862
3876
  /**
3863
- * Waits for a network request.
3877
+ * Waits for a network response.
3864
3878
  *
3865
3879
  * ```js
3866
3880
  * I.waitForResponse('http://example.com/resource');
3867
- * I.waitForResponse(request => request.url() === 'http://example.com' && request.method() === 'GET');
3881
+ * I.waitForResponse(response => response.url() === 'https://example.com' && response.status() === 200);
3868
3882
  * ```
3869
3883
  * @param [sec = null] - number of seconds to wait
3870
3884
  */
@@ -3903,18 +3917,6 @@ declare namespace CodeceptJS {
3903
3917
  * See [Playwright's reference](https://playwright.dev/docs/api/class-page?_highlight=waitfornavi#pagewaitfornavigationoptions)
3904
3918
  */
3905
3919
  waitForNavigation(opts: any): void;
3906
- /**
3907
- * Waits for a function to return true (waits for 1sec by default).
3908
- *
3909
- * ```js
3910
- * I.waitUntil(() => window.requests == 0);
3911
- * I.waitUntil(() => window.requests == 0, 5);
3912
- * ```
3913
- * @param fn - function which is executed in browser context.
3914
- * @param [sec = 1] - (optional, `1` by default) time in seconds to wait
3915
- * @param [timeoutMsg = ''] - message to show in case of timeout fail.
3916
- */
3917
- waitUntil(fn: ((...params: any[]) => any) | string, sec?: number, timeoutMsg?: string, interval?: number): void;
3918
3920
  /**
3919
3921
  * Waits for an element to become not attached to the DOM on a page (by default waits for 1sec).
3920
3922
  * Element can be located by CSS or XPath.
@@ -4622,11 +4624,12 @@ declare namespace CodeceptJS {
4622
4624
  /**
4623
4625
  * Checks that title is equal to provided one.
4624
4626
  *
4625
- * ```js
4626
- * I.seeTitleEquals('Test title.');
4627
- * ```
4627
+ * ```js
4628
+ * I.seeTitleEquals('Test title.');
4629
+ * ```
4630
+ * @param text - value to check.
4628
4631
  */
4629
- seeTitleEquals(): void;
4632
+ seeTitleEquals(text: string): void;
4630
4633
  /**
4631
4634
  * Checks that title does not contain text.
4632
4635
  *
@@ -5156,18 +5159,6 @@ declare namespace CodeceptJS {
5156
5159
  * @param [sec = null] - (optional, `1` by default) time in seconds to wait
5157
5160
  */
5158
5161
  waitForFunction(fn: string | ((...params: any[]) => any), argsOrSec?: any[] | number, sec?: number): void;
5159
- /**
5160
- * Waits for a function to return true (waits for 1sec by default).
5161
- *
5162
- * ```js
5163
- * I.waitUntil(() => window.requests == 0);
5164
- * I.waitUntil(() => window.requests == 0, 5);
5165
- * ```
5166
- * @param fn - function which is executed in browser context.
5167
- * @param [sec = 1] - (optional, `1` by default) time in seconds to wait
5168
- * @param [timeoutMsg = ''] - message to show in case of timeout fail.
5169
- */
5170
- waitUntil(fn: ((...params: any[]) => any) | string, sec?: number, timeoutMsg?: string, interval?: number): void;
5171
5162
  /**
5172
5163
  * Waiting for the part of the URL to match the expected. Useful for SPA to understand that page was changed.
5173
5164
  *
@@ -5634,11 +5625,12 @@ declare namespace CodeceptJS {
5634
5625
  /**
5635
5626
  * Checks that title is equal to provided one.
5636
5627
  *
5637
- * ```js
5638
- * I.seeTitleEquals('Test title.');
5639
- * ```
5628
+ * ```js
5629
+ * I.seeTitleEquals('Test title.');
5630
+ * ```
5631
+ * @param text - value to check.
5640
5632
  */
5641
- seeTitleEquals(): void;
5633
+ seeTitleEquals(text: string): void;
5642
5634
  /**
5643
5635
  * Checks that title does not contain text.
5644
5636
  *
@@ -6847,18 +6839,6 @@ declare namespace CodeceptJS {
6847
6839
  * See [Pupeteer's reference](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitfornavigationoptions)
6848
6840
  */
6849
6841
  waitForNavigation(opts: any): void;
6850
- /**
6851
- * Waits for a function to return true (waits for 1sec by default).
6852
- *
6853
- * ```js
6854
- * I.waitUntil(() => window.requests == 0);
6855
- * I.waitUntil(() => window.requests == 0, 5);
6856
- * ```
6857
- * @param fn - function which is executed in browser context.
6858
- * @param [sec = 1] - (optional, `1` by default) time in seconds to wait
6859
- * @param [timeoutMsg = ''] - message to show in case of timeout fail.
6860
- */
6861
- waitUntil(fn: ((...params: any[]) => any) | string, sec?: number, timeoutMsg?: string, interval?: number): void;
6862
6842
  /**
6863
6843
  * Waits for an element to become not attached to the DOM on a page (by default waits for 1sec).
6864
6844
  * Element can be located by CSS or XPath.
@@ -6971,8 +6951,9 @@ declare namespace CodeceptJS {
6971
6951
  * ```js
6972
6952
  * I.setRequestTimeout(10000); // In milliseconds
6973
6953
  * ```
6954
+ * @param newTimeout - timeout in milliseconds
6974
6955
  */
6975
- setRequestTimeout(): void;
6956
+ setRequestTimeout(newTimeout: number): void;
6976
6957
  /**
6977
6958
  * Send GET request to REST API
6978
6959
  *
@@ -8422,7 +8403,7 @@ declare namespace CodeceptJS {
8422
8403
  * ```
8423
8404
  * @param timeouts - WebDriver timeouts object.
8424
8405
  */
8425
- defineTimeout(timeouts: WebdriverIO.Timeouts): void;
8406
+ defineTimeout(timeouts: any): void;
8426
8407
  /**
8427
8408
  * Opens a web page in a browser. Requires relative or absolute url.
8428
8409
  * If url starts with `/`, opens a web page of a site defined in `url` config parameter.
@@ -9642,18 +9623,6 @@ declare namespace CodeceptJS {
9642
9623
  * @param [sec = null] - (optional, `1` by default) time in seconds to wait
9643
9624
  */
9644
9625
  waitForFunction(fn: string | ((...params: any[]) => any), argsOrSec?: any[] | number, sec?: number): void;
9645
- /**
9646
- * Waits for a function to return true (waits for 1sec by default).
9647
- *
9648
- * ```js
9649
- * I.waitUntil(() => window.requests == 0);
9650
- * I.waitUntil(() => window.requests == 0, 5);
9651
- * ```
9652
- * @param fn - function which is executed in browser context.
9653
- * @param [sec = 1] - (optional, `1` by default) time in seconds to wait
9654
- * @param [timeoutMsg = ''] - message to show in case of timeout fail.
9655
- */
9656
- waitUntil(fn: ((...params: any[]) => any) | string, sec?: number, timeoutMsg?: string, interval?: number): void;
9657
9626
  /**
9658
9627
  * Switches frame or in case of null locator reverts to parent.
9659
9628
  *
@@ -9805,6 +9774,11 @@ declare namespace CodeceptJS {
9805
9774
  * add print comment method`
9806
9775
  */
9807
9776
  say(msg: string, color?: string): Promise<any> | undefined;
9777
+ /**
9778
+ * set the maximum execution time for the next step
9779
+ * @param timeout - step timeout in seconds
9780
+ */
9781
+ limitTime(timeout: number): this;
9808
9782
  retry(opts?: any): this;
9809
9783
  }
9810
9784
  /**
@@ -10180,11 +10154,11 @@ declare namespace CodeceptJS {
10180
10154
  /**
10181
10155
  * Filters to modify locators
10182
10156
  */
10183
- static filters: any;
10157
+ static filters: ((arg0: CodeceptJS.LocatorOrString, arg1: Locator) => void)[];
10184
10158
  /**
10185
10159
  * Appends new `Locator` filter to an `Locator.filters` array, and returns the new length of the array.
10186
10160
  */
10187
- static addFilter(): void;
10161
+ static addFilter(fn: (...params: any[]) => any): number;
10188
10162
  }
10189
10163
  namespace output {
10190
10164
  var stepShift: number;
@@ -10274,7 +10248,7 @@ declare namespace CodeceptJS {
10274
10248
  * true: it will retries if `retryOpts` set.
10275
10249
  * false: ignore `retryOpts` and won't retry.
10276
10250
  */
10277
- add(taskName: string | ((...params: any[]) => any), fn?: (...params: any[]) => any, force?: boolean, retry?: boolean): Promise<any> | undefined;
10251
+ add(taskName: string | ((...params: any[]) => any), fn?: (...params: any[]) => any, force?: boolean, retry?: boolean, timeout?: number): Promise<any> | undefined;
10278
10252
  retry(opts: any): any;
10279
10253
  catch(customErrFn?: (...params: any[]) => any): Promise<any>;
10280
10254
  catchWithoutStop(customErrFn: (...params: any[]) => any): Promise<any>;
@@ -10337,6 +10311,7 @@ declare namespace CodeceptJS {
10337
10311
  args: any[];
10338
10312
  metaStep: MetaStep;
10339
10313
  stack: string;
10314
+ totalTimeout: number;
10340
10315
  setTrace(): void;
10341
10316
  setArguments(args: any[]): void;
10342
10317
  run(...args: any[]): any;
@@ -10358,6 +10333,7 @@ declare namespace CodeceptJS {
10358
10333
  */
10359
10334
  namespace store {
10360
10335
  var debugMode: boolean;
10336
+ var timeouts: boolean;
10361
10337
  }
10362
10338
  /**
10363
10339
  * Describe a "suite" with the given `title`
package/docs/angular.md DELETED
@@ -1,325 +0,0 @@
1
- ---
2
- permalink: /angular
3
- title: Testing with Protractor
4
- ---
5
-
6
- # Protractor Testing with CodeceptJS
7
-
8
- ## Introduction
9
-
10
- CodeceptJS is an acceptance testing framework. In the diversified world of JavaScript testing libraries, it aims to create a unified high-level API for end-to-end testing, powered by a variety of backends.
11
- CodeceptJS allows you to write a test and switch the execution driver via config: whether it's *wedriverio*, *puppeteer*, or *protractor* depends on you.
12
- This way you aren't bound to a specific implementation, and your acceptance tests will work no matter what framework is running them.
13
-
14
- [Protractor](http://www.protractortest.org/#/) is an official tool for testing AngularJS applications.
15
- CodeceptJS should not be considered as alternative to Protractor, but rather a testing framework that leverages this powerful library.
16
-
17
- ![angular-protractor](/img/angular-protractor.png)
18
-
19
- There is no magic in testing of AngularJS application in CodeceptJS.
20
- You just execute regular Protractor commands, packaged into a simple, high-level API.
21
-
22
- ![todo-mvc](/img/todo.png)
23
-
24
- As an example, we will use the popular [TodoMVC application](http://todomvc.com/examples/angularjs/#/).
25
- How would we test creating a new todo item using CodeceptJS?
26
-
27
- ```js
28
- Scenario('create todo item', ({ I }) => {
29
- I.amOnPage('/');
30
- I.dontSeeElement('#todo-count');
31
- I.fillField({model: 'newTodo'}, 'Write a guide');
32
- I.pressKey('Enter');
33
- I.see('Write a guide', {repeater: "todo in todos"});
34
- I.see('1 item left', '#todo-count');
35
- });
36
- ```
37
-
38
- A similar test written using Protractor's native syntax (inherited from selenium-webdriver) would look like this:
39
-
40
- ```js
41
- it('should create todo item', (I) => {
42
- browser.get("http://todomvc.com/examples/angularjs/#/");
43
- expect(element(by.css("#todo-count")).isPresent()).toBeFalsy();
44
- var inputField = element(by.model("newTodo"));
45
- inputField.sendKeys("Write a guide");
46
- inputField.sendKeys(protractor.Key.ENTER);
47
- var todos = element.all(by.repeater("todo in todos"));
48
- expect(todos.last().getText()).toEqual("Write a guide"));
49
- element(by.css("#todo-count")).getText()).toContain('1 items left');
50
- });
51
- ```
52
-
53
- Compared to the API proposed by CodeceptJS, the Protractor code looks more complicated.
54
- Even more important, it's harder to read and follow the logic of the Protractor test.
55
- Readability is a crucial part of acceptance testing.
56
- Tests should be easy to modify when there are changes in the specification or design.
57
- If the test is written in Protractor, it would likely require someone familiar with Protractor to make the change, whereas CodeceptJS allows anyone to understand and modify the test.
58
- CodeceptJS provides scenario-driven approach, so a test is just a step-by-step representation of real user actions.
59
- This means you can easily read and understand the steps in a test scenario, and edit the steps when the test needs to be changed.
60
-
61
- In this way, CodeceptJS is similar to Cucumber. If you run a test with `--steps` option you will see this output:
62
-
63
- ```bash
64
- TodoMvc --
65
- create todo item
66
- • I am on page "/"
67
- • I dont see element "#todo-count"
68
- • I fill field {"model":"newTodo"}, "Write a guide"
69
- • I press key "Enter"
70
- • I see "Write a guide", {"repeater":"todo in todos"}
71
- • I see "1 item left", "#todo-count"
72
- ✓ OK in 968ms
73
- ```
74
-
75
- Unlike Cucumber, CodeceptJS is not about writing test scenarios to satisfy business rules or requirements.
76
- Instead, its **goal is to provide standard action steps you can use for testing applications**.
77
- Although it can't cover 100% of use cases, CodeceptJS aims for 90%. For the remainder, you can write your own steps inside a [custom Helper](http://codecept.io/helpers/) using Protractor's API.
78
-
79
- ### Setting up CodeceptJS with Protractor
80
-
81
- To start using CodeceptJS you will need to install it via NPM and initialize it in a directory with tests.
82
-
83
- ```bash
84
- npm install codeceptjs --save
85
- npx codeceptjs init
86
- ```
87
-
88
- You will be asked questions about the initial configuration, make sure you select the Protractor helper.
89
- If your project didn't already have the Protractor library, it **will be installed** as part of this process.
90
- Please agree to extend steps, and use `http://todomvc.com/examples/angularjs/` as the url for Protractor helper.
91
-
92
- For TodoMVC application, you will have following config created in the `codecept.conf.js` file:
93
-
94
- ```js
95
- exports.config = { tests: './*_test.js',
96
- timeout: 10000,
97
- output: './output',
98
- helpers:
99
- { Protractor:
100
- { url: 'http://todomvc.com/examples/angularjs/',
101
- driver: 'hosted',
102
- browser: 'chrome',
103
- rootElement: 'body' } },
104
- include: { I: './steps_file.js' },
105
- bootstrap: false,
106
- mocha: {},
107
- name: 'todoangular'
108
- }
109
- ```
110
-
111
- Your first test can be generated with the `gt` command:
112
-
113
- ```bash
114
- npx codeceptjs gt
115
- ```
116
-
117
- After that, you can start writing your first CodeceptJS/Angular tests.
118
- Please refer to the [Protractor helper](http://codecept.io/helpers/Protractor/) documentation for a list of all available actions.
119
- You can also run the `list` command to see methods of I:
120
-
121
- ```bash
122
- npx codeceptjs list
123
- ```
124
-
125
- ## Starting Selenium Server
126
-
127
- Protractor requires Selenium Server to be started and running. To start and stop Selenium automatically install `@wdio/selenium-standalone-service`.
128
-
129
- ```
130
- npm i @wdio/selenium-standalone-service --save
131
- ```
132
-
133
- Enable it in the `codecept.conf.js` file, inside the plugins section:
134
-
135
- ```js
136
- exports.config = {
137
- // ...
138
- // inside codecept.conf.js
139
- plugins: {
140
- wdio: {
141
- enabled: true,
142
- services: ['selenium-standalone']
143
- }
144
- }
145
- }
146
- ```
147
-
148
- ## Testing non-Angular Applications
149
-
150
- Protractor can also be used to test applications built without AngularJS. In this case, you need to disable the angular synchronization feature inside the config:
151
-
152
- ```js
153
- helpers: {
154
- Protractor: {
155
- url: "http://todomvc.com/examples/angularjs/",
156
- driver: "hosted",
157
- browser: "firefox",
158
- angular: false
159
- }
160
- }
161
- ```
162
-
163
- ## Writing Your First Test
164
-
165
- Your test scenario should always use the `I` object to execute commands.
166
- This is important, as all methods of `I` are running in the global promise chain. This way, CodeceptJS makes sure everything is executed in right order.
167
- To start with opening a webpage, use the `amOnPage` command for. Since we already specified the full URL to the TodoMVC app, we can pass the relative path for our url, instead of the absolute url:
168
-
169
- ```js
170
- Feature('Todo MVC');
171
-
172
- Scenario('create todo item', ({ I }) => {
173
- I.amOnPage('/');
174
- });
175
- ```
176
-
177
- All scenarios should describe actions on the site, with assertions at the end. In CodeceptJS, assertion commands have the `see` or `dontSee` prefix:
178
-
179
- ```js
180
- Feature('Todo MVC');
181
-
182
- Scenario('create todo item', ({ I }) => {
183
- I.amOnPage('/');
184
- I.dontSeeElement('#todo-count');
185
- });
186
- ```
187
-
188
- A test can be executed with the `run` command, we recommend using the `--steps` option to print out the step-by-step execution:
189
-
190
- ```sh
191
- npx codeceptjs run --steps
192
- ```
193
-
194
- ```
195
- Test root is assumed to be /home/davert/demos/todoangular
196
- Using the selenium server at http://localhost:4444/wd/hub
197
-
198
- TodoMvc --
199
- create todo item
200
- • I am on page "/"
201
- • I dont see element "#todo-count"
202
- ```
203
-
204
- ## Running Several Scenarios
205
-
206
- By now, you should have a test similar to the one shown in the beginning of this guide. We probably want to have multiple tests though, like testing the editing of todo items, checking todo items, etc.
207
-
208
- Let's prepare our test to contain multiple scenarios. All of our test scenarios will need to to start with with the main page of application open, so `amOnPage` can be moved into the `Before` hook:
209
- Our scenarios will also probably deal with created todo items, so we can move the logic of creating a new todo into a function.
210
-
211
- ```js
212
- Feature('TodoMvc');
213
-
214
- Before(({ I }) => {
215
- I.amOnPage('/');
216
- });
217
-
218
- const createTodo = function (I, name) {
219
- I.fillField({model: 'newTodo'}, name);
220
- I.pressKey('Enter');
221
- }
222
-
223
- Scenario('create todo item', ({ I }) => {
224
- I.dontSeeElement('#todo-count');
225
- createTodo(I, 'Write a guide');
226
- I.see('Write a guide', {repeater: "todo in todos"});
227
- I.see('1 item left', '#todo-count');
228
- });
229
- ```
230
-
231
- and now we can add even more tests!
232
-
233
- ```js
234
- Scenario('edit todo', ({ I }) => {
235
- createTodo(I, 'write a review');
236
- I.see('write a review', {repeater: "todo in todos"});
237
- I.doubleClick('write a review');
238
- I.pressKey(['Control', 'a']);
239
- I.pressKey('write old review');
240
- I.pressKey('Enter');
241
- I.see('write old review', {repeater: "todo in todos"});
242
- });
243
-
244
- Scenario('check todo item', ({ I }) => {
245
- createTodo(I, 'my new item');
246
- I.see('1 item left', '#todo-count');
247
- I.checkOption({model: 'todo.completed'});
248
- I.see('0 items left', '#todo-count');
249
- });
250
- ```
251
-
252
- > This example is [available on GitHub](https://github.com/DavertMik/codeceptjs-angular-todomvc).
253
-
254
-
255
- ## Locators
256
-
257
- You may have noticed that CodeceptJS doesn't use `by.*` locators which are common in Protractor or Selenium Webdriver.
258
- Instead, most methods expect you to pass valid CSS selectors or XPath. If you don't want CodeceptJS to guess the locator type, then you can specify the type using *strict locators*. This is the CodeceptJS version of `by`, so you can also reuse your angular specific locators (like models, repeaters, bindings, etc):
259
-
260
- ```sh
261
- {css: 'button'}
262
- {repeater: "todo in todos"}
263
- {binding: 'latest'}
264
- ```
265
-
266
- When dealing with clicks, we can specify a text value. CodeceptJS will use that value to search the web page for a valid clickable element containing our specified text.
267
- This enables us to search for links and buttons by their text.
268
-
269
- The same is true for form fields: they can be searched by field name, label, and so on.
270
-
271
- Using smart locators makes tests easier to write, however searching an element by text is slower than searching via CSS|XPath, and is much slower than using strict locators.
272
-
273
- ## Refactoring
274
-
275
- In the previous examples, we moved actions into the `createTodo` function. Is there a more elegant way of refactoring?
276
- Can we instead write a function like `I.createTodo()` which we can reuse? In fact, we can do so by editing the `steps_file.js` file created by the init command.
277
-
278
- ```js
279
- // in this file you can append custom step methods to 'I' object
280
-
281
- module.exports = function() {
282
- return actor({
283
- createTodo: function(title) {
284
- this.fillField({model: 'newTodo'}, title);
285
- this.pressKey('Enter');
286
- }
287
- });
288
- }
289
- ```
290
-
291
- That's it, our method is now available to use as `I.createTodo(title)`:
292
-
293
- ```js
294
- Scenario('create todo item', ({ I }) => {
295
- I.dontSeeElement('#todo-count');
296
- I.createTodo('Write a guide');
297
- I.see('Write a guide', {repeater: "todo in todos"});
298
- I.see('1 item left', '#todo-count');
299
- });
300
- ```
301
-
302
- To learn more about refactoring options in CodeceptJS read [PageObjects guide](http://codecept.io/pageobjects/).
303
-
304
-
305
- ## Extending
306
-
307
- What if CodeceptJS doesn't provide some specific Protractor functionality you need? If you don't know how to do something with CodeceptJS, you can simply revert back to using Protractor syntax!
308
-
309
- Create a custom helper, define methods for it, and use it inside the I object. Your Helper can access `browser` from Protractor
310
- by accessing the Protractor helper:
311
-
312
- ```js
313
- let browser = this.helpers['Protractor'].browser;
314
- ```
315
-
316
- or use global `element` and `by` variables to locate elements:
317
-
318
- ```js
319
- element.all(by.repeater('result in memory'));
320
- ```
321
-
322
- This is the recommended way to implement all custom logic using low-level Protractor syntax in order to reuse it inside of test scenarios.
323
- For more information, see an [example of such a helper](http://codecept.io/helpers/#protractor-example).
324
-
325
-