Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

Commit

Permalink
fix(doc): update doc for testing with node 8 async/await and chrome i…
Browse files Browse the repository at this point in the history
…nspector. (#4613)
  • Loading branch information
qiyigg committed Dec 6, 2017
1 parent 5d13b00 commit e51f0ec
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 84 deletions.
37 changes: 37 additions & 0 deletions debugging/async_await.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
describe('angularjs homepage', function() {
it('should greet the named user', async function() {
debugger;
await browser.get('http://www.angularjs.org');

await element(by.model('yourName')).sendKeys('Julie');

var greeting = element(by.binding('yourName'));

expect(await greeting.getText()).toEqual('Hello Julie!');
});

describe('todo list', function() {
var todoList;

beforeEach(async function() {
await browser.get('http://www.angularjs.org');
todoList = element.all(by.repeater('todo in todoList.todos'));
});

it('should list todos', async function() {
expect(await todoList.count()).toEqual(2);
expect(await todoList.get(1).getText()).toEqual('build an AngularJS app');
});

it('should add a todo', async function() {
var addTodo = element(by.model('todoList.todoText'));
var addButton = element(by.css('[value="add"]'));

await addTodo.sendKeys('write a protractor test');
await addButton.click();

expect(await todoList.count()).toEqual(3);
expect(await todoList.get(2).getText()).toEqual('write a protractor test');
});
});
});
25 changes: 25 additions & 0 deletions debugging/conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// An example configuration file for debugging test using async/await.
exports.config = {
directConnect: true,

// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},

seleniumAddress: 'http://localhost:4444/wd/hub',

// Framework to use. Jasmine is recommended.
framework: 'jasmine',

// Spec patterns are relative to the current working directory when
// protractor is called.
specs: ['async_await.js'],

SELENIUM_PROMISE_MANAGER: false,

// Options to be passed to Jasmine.
jasmineNodeOpts: {
defaultTimeoutInterval: 30000
}
};
84 changes: 83 additions & 1 deletion docs/async-await.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,86 @@
`async`/`await`
===============

Please see [our TypeScript examples which use `async`/`await`](/exampleTypescript/asyncAwait/).
**Background**

- The Web Driver Control Flow is used to synchronize your commands so they reach
the browser in the correct order (see
[/docs/control-flow.md](/docs/control-flow.md) for details). In the future, the
control flow is being removed (see [SeleniumHQ's github issue](
https://github.com/SeleniumHQ/selenium/issues/2969) for details). Instead of the
control flow, you can synchronize your commands with promise chaining or the
upcoming ES7 feature `async`/`await`.

- Previously, we have Typescript support for `async`/`await`: Please see [TypeScript examples which use `async`/`await`](/exampleTypescript/asyncAwait/README.md).

- The latest [Node.js](https://nodejs.org/en/) provides native async/await,
which means we can get stable e2e test without using control flow in javascript test.

**Note**: To write and run native async/await test, the node.js version should be greater than or equal to 8.0, and Jasmine version should be greater than or equal to 2.7

- If we disable control flow and use async/await to write tests, we can get a
better debugging experience by using [chrome
inspector](./debugging.md#disabled-control-flow)

**How to use native async/await in test**

We have a simple example to show how to use async/await in test.

You can find the whole example in
[here](/debugging/async_await.js)

```javascript
describe('angularjs homepage', function() {
it('should greet the named user', async function() {
await browser.get('http://www.angularjs.org');

await element(by.model('yourName')).sendKeys('Julie');

var greeting = element(by.binding('yourName'));

expect(await greeting.getText()).toEqual('Hello Julie!');
});
```
As you can see, the syntax is almost the same with TypeScript async/await.
1. We need wrap our asynchronous function with “async”.
1. We can add “await” keyword to each operation that we want our program to
wait for.
**Note:** Never forget to add “await” keyword in an async function, it
may bring some unexpected problem (e.g. your test might fail silently and
always be reported as passed).
1. Don’t forget to turn off control_flow, you cannot use a mix of `async`/`await` and the control flow:
`async`/`await` causes the control flow to become unreliable (see
[github issue]( https://github.com/SeleniumHQ/selenium/issues/3037)). So if you
`async`/`await` anywhere in a spec, you should use the
`SELENIUM_PROMISE_MANAGER: false`
```javascript
// An example configuration file for debugging test using async/await.
exports.config = {
directConnect: true,

// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},

seleniumAddress: 'http://localhost:4444/wd/hub',

// Framework to use. Jasmine is recommended.
framework: 'jasmine',

// Spec patterns are relative to the current working directory when
// protractor is called.
specs: ['async_await.js'],

SELENIUM_PROMISE_MANAGER: false,

// Options to be passed to Jasmine.
jasmineNodeOpts: {
defaultTimeoutInterval: 30000
}
};
```
Binary file added docs/breakpoint.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chromeDevTool.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
180 changes: 121 additions & 59 deletions docs/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ state of the application they're testing. WebDriver tests in particular
can be difficult to debug because of long error messages and the separation
between the browser and the process running the test.

Types of Failure
----------------
## Types of Failure

Protractor comes with examples of failing tests ([failure_spec.js](https://github.com/angular/protractor/blob/master/debugging/failure_spec.js)).
To run, start up the test application and a Selenium Server, and run the command below. Then look at all the stack traces.
Expand All @@ -28,15 +27,125 @@ This test suite shows various types of failure:
like.


Timeouts
--------
## Timeouts

There are several ways that Protractor can time out. See the [Timeouts](/docs/timeouts.md)
reference for full documentation.

## Disabled Control Flow

Pausing to Debug
----------------

The latest [Node.js](https://nodejs.org/en/) provides native async/await, which
means we can get stable e2e test easily without using control flow. Furthermore,
if we write our test by using async/await[(how to?)](./async-await.md), we can
use chrome development tool and chrome inspector together to debug the new
tests, which will give a nicer debugging experience.

**Debuging tests in chrome inspector**

We can debug both javascript and TypeScript async/await tests in chrome
inspector and the debugging process is almost the same.

We have a simple example to show how to debug async/await in test. You can find
the whole example in
[here](../debugging/async_await.js)

- Add “debugger” keyword to the test case that we want to debug.

```javascript
it('should greet the named user', async function() {
debugger;
await browser.get('http://www.angularjs.org');

await element(by.model('yourName')).sendKeys('Julie');

var greeting = element(by.binding('yourName'));

expect(await greeting.getText()).toEqual('Hello Julie!');
});
```

- Start test process with a new argument "inspect-brk", which will enable
inspector agent, listen on default address and port (127.0.0.1:9229) and
break before user code starts

Use

```
node --inspect-brk bin/protractor <config_file>
```

- Open chrome inspector: Enter "chrome://inspect/#devices" in browser, find
the current running target and click “Inspect”

![screenshot](./inspector.png)

- The test will start and pause at the beginning.

![screenshot](./firstBreak.png)

- We can click F8 (resume script execution), and the test will pause at the
first line that has our “debuggerkeyword. We can then add breakpoints and
debug tests.

![screenshot](./breakpoint.png)

- We can also open chrome development tool on the webdriver controlled browser
to check the html elements and do some queries while the test execution is
pausing.

![screenshot](./chromeDevTool.png)

- Known Issues

1. If we resume test execution after a long time pause, it will jump to next
test case even we have some other breaking points in current test case since
current test case has already been timeout. You can set
jasmine.DEFAULT_TIMEOUT_INTERVAL to an arbitrary high value so that your
test doesn't time out.
2. If we step into protractor lib code which was written in Typescript, we
cannot see the TypeScript code. In general, you can add breakpoints to each
line that you want it to pause, and use F8 (resume script execution) to
debug(To avoid step into protractor lib).
**Setting Up VSCode for Debugging**
VS Code has built-in [debugging](https://code.visualstudio.com/docs/editor/debugging) support for the Node.js runtime and can debug JavaScript, TypeScript, and any other language that gets transpiled to JavaScript.
To set up VSCode for Protractor, follow the below steps:
1. Click on the Debugging icon in the View Bar on the side of VS Code.
2. Click on the Configure gear icon on the Debug view top bar and choose nodejs environment.
3. It will generate a `launch.json` file under your workspace's `.vscode` folder.
4. Setup your launch.json file by configuring below two commands:
```
"program": "${workspaceRoot}/node_modules/protractor/bin/protractor",
"args": ["${workspaceRoot}/protractorConfig.js"],
```
5. Save your launch.json, put some breakpoints and start debugging.
**Setting Up WebStorm for Debugging**
To set up WebStorm for Protractor, do the following:
1. Open the Run/Debug Configurations dialog
2. Add new Node.js configuration.
3. On the Configuration tab set:
- **Node Interpreter**: path to node executable
- **Working directory**: your project base path
- **JavaScript file**: path to Protractor cli.js file (e.g. *node_modules\protractor\built\cli.js*)
- **Application parameters**: path to your Protractor configuration file (e.g.
*protractorConfig.js*)
4. Click OK, place some breakpoints, and start debugging.
## Enabled Control Flow
**Note:** Protractor debugger and element explorer cannot be used for Node.js 8+
**Pausing to Debug**
Protractor supports two methods for pausing to debug - `browser.pause()` and
`browser.debugger()`. You probably want to use `browser.pause()`, unless you
Expand Down Expand Up @@ -149,53 +258,7 @@ used from the browser's console.
> window.clientSideScripts.findInputs('username', document.getElementById('#myEl'));
```

**Debugging with the control flow disabled**

If you've set the `SELENIUM_PROMISE_MANAGER` config value to false to [disable the control flow](https://github.com/angular/protractor/blob/master/docs/control-flow.md),
the above methods will not work. Instead, you can now use native `debugger` statements to pause your code. However, you
will need to start your tests using Node's `--inspect-brk` option:

```
node --inspect-brk node_modules/.bin/protractor <config_file>
```

You will then be able to use the Chrome devtools at chrome://inspect to connect to the tests.


Setting Up VSCode for Debugging
-------------------------------
VS Code has built-in [debugging](https://code.visualstudio.com/docs/editor/debugging) support for the Node.js runtime and can debug JavaScript, TypeScript, and any other language that gets transpiled to JavaScript.

To set up VSCode for Protractor, follow the below steps:

1. Click on the Debugging icon in the View Bar on the side of VS Code.
2. Click on the Configure gear icon on the Debug view top bar and choose nodejs environment.
3. It will generate a `launch.json` file under your workspace's `.vscode` folder.
4. Setup your launch.json file by configuring below two commands:
```
"program": "${workspaceRoot}/node_modules/protractor/bin/protractor",
"args": ["${workspaceRoot}/protractorConfig.js"],
```
5. Save your launch.json, put some breakpoints and start debugging.

Setting Up WebStorm for Debugging
---------------------------------

To set up WebStorm for Protractor, do the following:

1. Open the Run/Debug Configurations dialog
2. Add new Node.js configuration.
3. On the Configuration tab set:
- **Node Interpreter**: path to node executable
- **Working directory**: your project base path
- **JavaScript file**: path to Protractor cli.js file (e.g. *node_modules\protractor\built\cli.js*)
- **Application parameters**: path to your Protractor configuration file (e.g.
*protractorConfig.js*)
4. Click OK, place some breakpoints, and start debugging.


Testing Out Protractor Interactively
------------------------------------
**Testing Out Protractor Interactively**

When debugging or first writing test suites, you may find it helpful to
try out Protractor commands without starting up the entire test suite. You can
Expand All @@ -222,8 +285,8 @@ matching a locator.

Element explorer will start chrome by default. However, you can specify
another browser, change browser settings, or specify any other config that you
normally would with your protractor test. To do this, pass configs to
protractor like you normally would,
normally would with your protractor test. To do this, pass configs to
protractor like you normally would,
but with the `--elementExplorer` flag set:

protractor [configFile] [options] --elementExplorer
Expand All @@ -232,16 +295,15 @@ For example, to connect to ChromeDriver directly, use

protractor --directConnect --elementExplorer

Element explore will ignore your specs, not set up your framework (e.g. jasmine,
Element explore will ignore your specs, not set up your framework (e.g. jasmine,
mocha, cucumber), and only allow you to pass in 1 capability, but will honor
every other parameter in your config.

Note `baseUrl` is used here as the initial page, i.e. element explorer will try
Note `baseUrl` is used here as the initial page, i.e. element explorer will try
to navigate to `baseUrl` automatically on start.


Taking Screenshots
------------------
## Taking Screenshots

WebDriver can snap a screenshot with `browser.takeScreenshot()`. This can be a
good way to help debug tests, especially for tests that run on a continuous integration
Expand Down
Binary file added docs/firstBreak.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/inspector.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit e51f0ec

Please sign in to comment.