自动化端对端测试框架-Protractor Test

Getting Started

To get started quickly, begin with the Tutorial which provides a step by step overview of how to install Protractor, create test files, set up config files, and run tests.

Protractor needs two files to run, the test or spec file, and the configuration file. For additional information, see Working with Spec and Config Files.

When writing tests, keep in mind that Protractor is a wrapper around WebDriverJS. You may want to skim through the WebDriverJS Users Guidebefore writing any tests.

The WebDriverJS API is based on promises. To learn more, check out The WebDriver Control Flow.

To learn how Protractor, Selenium Server, and Selenium WebDriver work together, take a look at How It Works

Once you are familiar with Protractor, it is recommended that you start using Page Objects. For more information see Using Page Objects to Organize Tests.

For a complete list of the Protractor documentation, see the Table of Contents.

Tutorial

This is a simple tutorial that shows you how to set up Protractor and start running tests.

Prerequisites

Protractor is a Node.js program. To run, you will need to have Node.js installed. You will download Protractor package using npm, which comes with Node.js. Check the version of Node.js you have by running node --version. It should be greater than v0.10.0.

By default, Protractor uses the Jasmine test framework for its testing interface. This tutorial assumes some familiarity with Jasmine, and we will use version 2.3.

This tutorial will set up a test using a local standalone Selenium Server to control browsers. You will need to have the Java Development Kit (JDK)installed to run the standalone Selenium Server. Check this by running java -version from the command line.

Setup

Use npm to install Protractor globally with:

npm install -g protractor

This will install two command line tools, protractor and webdriver-manager. Try running protractor --version to make sure it's working.

The webdriver-manager is a helper tool to easily get an instance of a Selenium Server running. Use it to download the necessary binaries with:

webdriver-manager update

Now start up a server with:

webdriver-manager start

This will start up a Selenium Server and will output a bunch of info logs. Your Protractor test will send requests to this server to control a local browser. Leave this server running throughout the tutorial. You can see information about the status of the server at http://localhost:4444/wd/hub.

Step 0 - write a test

Open a new command line or terminal window and create a clean folder for testing.

Protractor needs two files to run, a spec file and a configuration file

Let's start with a simple test that navigates to an example AngularJS application and checks its title. We’ll use the Super Calculator application at http://juliemr.github.io/protractor-demo/.

Copy the following into spec.js:

// spec.jsdescribe('Protractor Demo App', function() {
  it('should have a title', function() {
    browser.get('http://juliemr.github.io/protractor-demo/');

    expect(browser.getTitle()).toEqual('Super Calculator');
  });});

The describe and it syntax is from the Jasmine framework. browser is a global created by Protractor, which is used for browser-level commands such as navigation with browser.get.

Now create the configuration file. Copy the following into conf.js:

// conf.jsexports.config = {
  framework: 'jasmine',
  seleniumAddress: 'http://localhost:4444/wd/hub',
  specs: ['spec.js']}

This configuration tells Protractor where your test files (specs) are, and where to talk to your Selenium Server (seleniumAddress). It specifies that we will be using Jasmine for the test framework. It will use the defaults for all other configuration. Chrome is the default browser.

Now run the test with

protractor conf.js

You should see a Chrome browser window open up and navigate to the Calculator, then close itself (this should be very fast!). The test output should be 1 tests, 1 assertion, 0 failures. Congratulations, you've run your first Protractor test!

Step 1 - interacting with elements

Now let's modify the test to interact with elements on the page. Change spec.js to the following:

// spec.jsdescribe('Protractor Demo App', function() {
  it('should add one and two', function() {
    browser.get('http://juliemr.github.io/protractor-demo/');
    element(by.model('first')).sendKeys(1);
    element(by.model('second')).sendKeys(2);

    element(by.id('gobutton')).click();

    expect(element(by.binding('latest')).getText()).
        toEqual('5'); // This is wrong!
  });});

This uses the globals element and by, which are also created by Protractor. The element function is used for finding HTML elements on your webpage. It returns an ElementFinder object, which can be used to interact with the element or get information from it. In this test, we use sendKeys to type into <input>s, click to click a button, and getText to return the content of an element.

element takes one parameter, a Locator, which describes how to find the element. The by object creates Locators. Here, we're using three types of Locators:

  • by.model('first') to find the element with ng-model="first". If you inspect the Calculator page source, you will see this is <input type=text ng-model="first">.

  • by.id('gobutton') to find the element with the given id. This finds <button id="gobutton">.

  • by.binding('latest') to find the element bound to the variable latest. This finds the span containing {{latest}}

    Learn more about locators and ElementFinders.

Run the tests with

protractor conf.js

You should see the page enter two numbers and wait for the result to be displayed. Because the result is 3, not 5, our test fails. Fix the test and try running it again.

Step 2 - writing multiple scenarios

Let's put these two tests together and clean them up a bit. Change spec.js to the following:

// spec.jsdescribe('Protractor Demo App', function() {
  var firstNumber = element(by.model('first'));
  var secondNumber = element(by.model('second'));
  var goButton = element(by.id('gobutton'));
  var latestResult = element(by.binding('latest'));

  beforeEach(function() {
    browser.get('http://juliemr.github.io/protractor-demo/');
  });

  it('should have a title', function() {
    expect(browser.getTitle()).toEqual('Super Calculator');
  });

  it('should add one and two', function() {
    firstNumber.sendKeys(1);
    secondNumber.sendKeys(2);

    goButton.click();

    expect(latestResult.getText()).toEqual('3');
  });

  it('should add four and six', function() {
    // Fill this in.
    expect(latestResult.getText()).toEqual('10');
  });});

Here, we've pulled the navigation out into a beforeEach function which is run before every it block. We've also stored the ElementFinders for the first and second input in nice variables that can be reused. Fill out the second test using those variables, and run the tests again to ensure they pass.

Step 3 - changing the configuration

Now that we've written some basic tests, let's take a look at the configuration file. The configuration file lets you change things like which browsers are used and how to connect to the Selenium Server. Let's change the browser. Change conf.js to the following:

// conf.jsexports.config = {
  framework: 'jasmine',
  seleniumAddress: 'http://localhost:4444/wd/hub',
  specs: ['spec.js'],
  capabilities: {
    browserName: 'firefox'
  }}

Try running the tests again. You should see the tests running on Firefox instead of Chrome. The capabilities object describes the browser to be tested against. For a full list of options, see the reference config file.

You can also run tests on more than one browser at once. Change conf.js to:

// conf.jsexports.config = {
  framework: 'jasmine',
  seleniumAddress: 'http://localhost:4444/wd/hub',
  specs: ['spec.js'],
  multiCapabilities: [{
    browserName: 'firefox'
  }, {
    browserName: 'chrome'
  }]}

Try running once again. You should see the tests running on Chrome and Firefox simultaneously, and the results reported separately on the command line.

Step 4 - lists of elements

Let's go back to the test files. Feel free to change the configuration back to using only one browser.

Sometimes, you will want to deal with a list of multiple elements. You can do this with element.all, which returns an ElementArrayFinder. In our calculator application, every operation is logged in the history, which is implemented on the site as a table with ng-repeat. Let's do a couple of operations, then test that they're in the history. Change spec.js to:

// spec.jsdescribe('Protractor Demo App', function() {
  var firstNumber = element(by.model('first'));
  var secondNumber = element(by.model('second'));
  var goButton = element(by.id('gobutton'));
  var latestResult = element(by.binding('latest'));
  var history = element.all(by.repeater('result in memory'));

  function add(a, b) {
    firstNumber.sendKeys(a);
    secondNumber.sendKeys(b);
    goButton.click();
  }

  beforeEach(function() {
    browser.get('http://juliemr.github.io/protractor-demo/');
  });

  it('should have a history', function() {
    add(1, 2);
    add(3, 4);

    expect(history.count()).toEqual(2);

    add(5, 6);

    expect(history.count()).toEqual(0); // This is wrong!
  });});

We've done a couple things here - first, we created a helper function, add. We've added the variable history. We use element.all with the by.repeater Locator to get an ElementArrayFinder. In our spec, we assert that the history has the expected length using the count method. Fix the test so that the second expectation passes.

ElementArrayFinder has many methods in addition to count. Let's use last to get an ElementFinder that matches the last element found by the Locator. Change the test to:

  it('should have a history', function() {
    add(1, 2);
    add(3, 4);

    expect(history.last().getText()).toContain('1 + 2');
    expect(history.first().getText()).toContain('foo'); // This is wrong!
  });

Since the Calculator reports the oldest result at the bottom, the oldest addition (1 + 2) be the last history entry. We're using the toContain Jasmine matcher to assert that the element text contains "1 + 2". The full element text will also contain the timestamp and the result. 

Fix the test so that it correctly expects the first history entry to contain the text "3 + 4".

ElementArrayFinder also has methods eachmapfilter, and reduce which are analogous to JavaScript Array methods. Read the API for more details.

Working with Spec and Config Files

Protractor needs two files to run, the test or spec file, and the configuration file.

Spec files

Protractor tests are written using the syntax of your test framework, for example Jasmine, and the Protractor API.

Example Spec File

This simple script (example_spec.js) tests the 'The Basics' example on the angularjs.org homepage.

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

    // Find the element with ng-model matching 'yourName' - this will
    // find the <input type="text" ng-model="yourName"/> element - and then
    // type 'Julie' into it.
    element(by.model('yourName')).sendKeys('Julie');

    // Find the element with binding matching 'yourName' - this will
    // find the <h1>Hello {{yourName}}!</h1> element.
    var greeting = element(by.binding('yourName'));

    // Assert that the text element has the expected value.
    // Protractor patches 'expect' to understand promises.

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

Global Variables

Protractor exports these global variables to your spec (test) file:

  • browser - A wrapper around an instance of WebDriver, used for navigation and page-wide information. The browser.get method loads a page. Protractor expects Angular to be present on a page, so it will throw an error if the page it is attempting to load does not contain the Angular library. (If you need to interact with a non-Angular page, you may access the wrapped webdriver instance directly with browser.driver).

  • element - A helper function for finding and interacting with DOM elements on the page you are testing. The element function searches for an element on the page. It requires one parameter, a locator strategy for locating the element. See Using Locators for more information. See Protractor's findelements test suite (elements_spec.js) for more examples.

  • by - A collection of element locator strategies. For example, elements can be found by CSS selector, by ID, or by the attribute they are bound to with ng-model. See Using Locators.

  • protractor - The Protractor namespace which wraps the WebDriver namespace. Contains static variables and classes, such as protractor.Key which enumerates the codes for special keyboard signals.

Config Files

The configuration file tells Protractor how to set up the Selenium Server, which tests to run, how to set up the browsers, and which test framework to use. The configuration file can also include one or more global settings.

Example Config File

A simple configuration (conf.js) is shown below.

// An example configuration fileexports.config = {
  // The address of a running selenium server.
  seleniumAddress: 'http://localhost:4444/wd/hub',

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

  // Spec patterns are relative to the configuration file location passed
  // to protractor (in this example conf.js).
  // They may include glob patterns.
  specs: ['example-spec.js'],

  // Options to be passed to Jasmine-node.
  jasmineNodeOpts: {
    showColors: true, // Use colors in the command line report.
  }};

Reference Config File

The reference config file file provides explanations for all of the Protractor configuration options. Default settings include the standalone Selenium Server, the Chrome browser, and the Jasmine test framework. Additional information about various configuration options is available here:

Setting Up the System Under Test

Protractor uses real browsers to run its tests, so it can connect to anything that your browser can connect to. This means you have great flexibility in deciding what you are actually testing. It could be a development server on localhost, a staging server up on your local network, or even production servers on the general internet. All Protractor needs is the URL. There are a couple of things to watch out for!

If your page does manual bootstrap Protractor will not be able to load your page using browser.get. Instead, use the base webdriver instance - browser.driver.get. This means that Protractor does not know when your page is fully loaded, and you may need to add a wait statement to make sure your tests avoid race conditions.

If your page uses $timeout for polling Protractor will not be able to tell when your page is ready. Consider using $interval instead of $timeout.

If you need to do global preparation for your tests (for example, logging in), you can put this into the config in the onPrepare property. This property can be either a function or a filename. If a filename, Protractor will load that file with Node.js and run its contents.

onPrepare can optionally return a promise, which Protractor will wait for before continuing execution. This can be used if the preparation involves any asynchronous calls, e.g. interacting with the browser. Otherwise Protractor cannot guarantee order of execution and may start the tests before preparation finishes.

See the login tests for an example.

Using Locators

The heart of end-to-end tests for webpages is finding DOM elements, interacting with them, and getting information about the current state of your application. This doc is an overview of how to locate and perform actions on DOM elements using Protractor.

Overview

Protractor exports a global function element, which takes a Locator and will return an ElementFinder. This function finds a single element - if you need to manipulate multiple elements, use the element.all function.

The ElementFinder has a set of action methods, such as click()getText(), and sendKeys. These are the core way to interact with an element and get information back from it.

When you find elements in Protractor all actions are asynchronous. Behind the scenes, all actions are sent to the browser being controlled using the JSON Webdriver Wire Protocol. The browser then performs the action as a user natively would.

Locators

A locator tells Protractor how to find a certain DOM element. Protractor exports locator factories on the global by object. The most common locators are:

// find an element using a css selectorby.css('.myclass') // find an element with the given idby.id('myid')// find an element with a certain ng-modelby.model('name')// find an element bound to the given variableby.binding('bindingname')

For a list of Protractor-specific locators, see the Protractor API: ProtractorBy.

The locators are passed to the element function, as below:

element(by.css('some-css'));element(by.model('item.name'));element(by.binding('item.name'));

When using CSS Selectors as a locator, you can use the shortcut $() notation:

$('my-css');// Is the same aselement(by.css('my-css'));

Actions

The element() function returns an ElementFinder object. The ElementFinder knows how to locate the DOM element using the locator you passed in as a parameter, but it has not actually done so yet. It will not contact the browser until an action method has been called.

The most common action methods are:

var el = element(locator);// Click on the elementel.click();// Send keys to the element (usually an input)el.sendKeys('my text');// Clear the text in an element (usually an input)el.clear();// Get the value of an attribute, for example, get the value of an inputel.getAttribute('value');

Since all actions are asynchronous, all action methods return a promise. So, to log the text of an element, you would do something like:

var el = element(locator);el.getText().then(function(text) {
  console.log(text);});

Any action available in WebDriverJS on a WebElement is available on an ElementFinder. See a full list.

Finding Multiple Elements

To deal with multiple DOM elements, use the element.all function. This also takes a locator as its only parameter.

element.all(by.css('.selector')).then(function(elements) {
  // elements is an array of ElementFinders.});

element.all() has several helper functions:

// Number of elements.element.all(locator).count();// Get by index (starting at 0).element.all(locator).get(index);// First and last.element.all(locator).first();element.all(locator).last();

Finding Sub-Elements

To find sub-elements, simply chain element and element.all functions together as shown below.

Using a single locator to find:

  • an element

     element(by.css('some-css'));
  • a list of elements:

     element.all(by.css('some-css'));

Using chained locators to find:

  • a sub-element:

     element(by.css('some-css')).element(by.tagName('tag-within-css'));
  • to find a list of sub-elements:

     element(by.css('some-css')).all(by.tagName('tag-within-css'));

You can chain with get/first/last as well like so:

element.all(by.css('some-css')).first().element(by.tagName('tag-within-css'));element.all(by.css('some-css')).get(index).element(by.tagName('tag-within-css'));element.all(by.css('some-css')).first().all(by.tagName('tag-within-css'));

Behind the Scenes: ElementFinders versus WebElements

If you're familiar with WebDriver and WebElements, or you're just curious about the WebElements mentioned above, you may be wondering how they relate to ElementFinders.

When you call driver.findElement(locator), WebDriver immediately sends a command over to the browser asking it to locate the element. This isn't great for creating page objects, because we want to be able to do things in setup (before a page may have been loaded) like

var myButton = ??;

and re-use the variable myButton throughout your test. ElementFinders get around this by simply storing the locator information until an action is called.

var myButton = element(locator);// No command has been sent to the browser yet.

The browser will not receive any commands until you call an action.

myButton.click();// Now two commands are sent to the browser - find the element, and then click it

ElementFinders also enable chaining to find subelements, such as element(locator1).element(locator2).

All WebElement actions are wrapped in this way and available on the ElementFinder, in addition to a couple helper methods like isPresent

You can always access the underlying WebElement using element(locator).getWebElement(), but you should not need to.

Using Page Objects to Organize Tests

When writing end-to-end tests, a common pattern is to use Page Objects. Page Objects help you write cleaner tests by encapsulating information about the elements on your application page. A Page Object can be reused across multiple tests, and if the template of your application changes, you only need to update the Page Object.

Without Page Objects

Here’s a simple test script (example_spec.js) for ‘The Basics’ example on the angularjs.org homepage.

describe('angularjs homepage', function() {
  it('should greet the named user', function() {
    browser.get('http://www.angularjs.org');
    element(by.model('yourName')).sendKeys('Julie');
    var greeting = element(by.binding('yourName'));
    expect(greeting.getText()).toEqual('Hello Julie!');
  });});

With PageObjects

To switch to Page Objects, the first thing you need to do is create a Page Object. A Page Object for ‘The Basics’ example on the angularjs.org homepage could look like this:

var AngularHomepage = function() {
  var nameInput = element(by.model('yourName'));
  var greeting = element(by.binding('yourName'));

  this.get = function() {
    browser.get('http://www.angularjs.org');
  };

  this.setName = function(name) {
    nameInput.sendKeys(name);
  };

  this.getGreeting = function() {
    return greeting.getText();
  };};

The next thing you need to do is modify the test script to use the PageObject and its properties. Note that the functionality of the test script itself does not change (nothing is added or deleted).

describe('angularjs homepage', function() {
  it('should greet the named user', function() {
    var angularHomepage = new AngularHomepage();
    angularHomepage.get();

    angularHomepage.setName('Julie');

    expect(angularHomepage.getGreeting()).toEqual('Hello Julie!');
  });});

Configuring Test Suites

It is possible to separate your tests into various test suites. In your config file, you could setup the suites option as shown below. 

exports.config = {
  // The address of a running selenium server.
  seleniumAddress: 'http://localhost:4444/wd/hub',

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

  // Spec patterns are relative to the location of the spec file. They may
  // include glob patterns.
  suites: {
    homepage: 'tests/e2e/homepage/**/*Spec.js',
    search: ['tests/e2e/contact_search/**/*Spec.js',
      'tests/e2e/venue_search/**/*Spec.js']
  },

  // Options to be passed to Jasmine-node.
  jasmineNodeOpts: {
    showColors: true, // Use colors in the command line report.
  }};

From the command line, you can then easily switch between running one or the other suite of tests. This command will run only the homepage section of the tests:

protractor protractor.conf.js --suite homepage

Additionally, you can run specific suites of tests with the command:

protractor protractor.conf.js --suite homepage,search

Debugging Protractor Tests

End-to-end tests can be difficult to debug because they depend on an entire system, may depend on prior actions (such as log-in), and may change the 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

Protractor comes with examples of failing tests (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.

protractor debugging/failureConf.js

This test suite shows various types of failure:

  • WebDriver throws an error - When a command cannot be completed, for example an element is not found.

  • Protractor will fail when it cannot find the Angular library on a page. If your test needs to interact with a non-angular page, access the WebDriver instance directly with browser.driver.

  • Expectation Failure - Shows what a normal expectation failure looks like.

Timeouts

There are several ways that Protractor can time out. See the Timeouts reference for full documentation.

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 would like precise control over the node debugger.

Using pause

Insert browser.pause() into your test where you want to pause.

it('should fail to find a non-existent element', function() {
  browser.get('app/index.html#/form');

  browser.pause();

  // This element doesn't exist, so this fails.
  var nonExistant = element(by.binding('nopenopenope')).getText();});

Run your tests normally.

protractor failureConf.js

The test will pause execution after the scheduled navigation to app/index.html#/form but before trying to get text from the nonnexistant element. The terminal will print instructions for continuing or inspecting the application and a list of the currently pending tasks on the WebDriver control flow.

-- WebDriver control flow schedule
 |- waiting for debugger to attach
 |---    at [object Object].<anonymous> (failure_spec.js:13:13)
 |- Protractor.waitForAngular()
 |---    at [object Object].<anonymous> (failure_spec.js:16:59)
wd-debug>

Enter c to move the test forward by one task. Enter repl to enter interactive mode. In interactive mode, you can send WebDriver commands to your browser. The resulting value or error will be reported to the terminal.

> element(by.binding('nopenopenope')).getText()
NoSuchElementError: No element found using locator: by.binding("nopenopenope")
>
> element(by.binding('user')).getText()
'Anon'

While the test is paused you may also interact with the browser. Note that if you open the Chrome Dev Tools, you must close them before continuing the test because ChromeDriver cannot operate when the Dev Tools are open.

When you finish debugging, exit by pressing Ctrl-C. Your tests will continue where they left off, using the same browser.

Using debugger

Insert browser.debugger(); into your test where you want to break:

it('should fail to find a non-existent element', function() {
  browser.get('app/index.html#/form');

  // Run this statement before the line which fails. If protractor is run
  // with the debugger (protractor debug <...>), the test
  // will pause after loading the webpage but before trying to find the
  // element.
  browser.debugger();

  // This element doesn't exist, so this fails.
  var nonExistant = element(by.binding('nopenopenope')).getText();});

Then run the test in debug mode:

protractor debug debugging/failureConf.js

This uses the node debugger. Enter c to start execution and continue after the breakpoint.

browser.debugger(); is different from from node's debugger; statement because it adds a breakpoint task asynchronous queue. This means the example above will pause after the get statement has been executing. Using debugger; pauses the test after the get command is scheduled but has not yet been executed.

Protractor's debugger() method works by scheduling a node debug breakpoint on the control flow.

When debugger() is called, it also inserts all the client side scripts from Protractor into the browser as window.clientSideScripts. They can be used from the browser's console.

// In the browser console (e.g. from Chrome Dev Tools)> window.clientSideScripts.findInputs('username');// Should return the input element with model 'username'.// You can also limit the scope of the locator> window.clientSideScripts.findInputs('username', document.getElementById('#myEl'));

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\lib\cli.js)

  • Application parameters: path to your Protractor configuration file (e.g. protractorConfig.js)

Click OK, place some breakpoints, and start debugging.

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 do this with the element explorer.

To run element explorer, simply run protractor as you normally would, but pass in the flag --elementExplorer:

protractor --elementExplorer

This will load up the URL on WebDriver and put the terminal into a REPL loop. You will see a > prompt. The browserelement and protractorvariables will be available. Enter a command such as:

> browser.get('http://www.angularjs.org')

or

> element(by.id('foobar')).getText()

Typing tab at a blank prompt will fill in a suggestion for finding elements. You can also use the list(locator) command to list all elements 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, but with the --elementExplorer flag set:

protractor [configFile] [options] --elementExplorer

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, 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 to navigate to baseUrl automatically on start.

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 server. The method returns a promise which will resolve to the screenshot as a base-64 encoded PNG.

Sample usage:

// at the top of the test spec:var fs = require('fs');// ... other code// abstract writing screen shot to a filefunction writeScreenShot(data, filename) {
    var stream = fs.createWriteStream(filename);

    stream.write(new Buffer(data, 'base64'));
    stream.end();}// ...// within a test:browser.takeScreenshot().then(function (png) {
    writeScreenShot(png, 'exception.png');});


转载于:https://my.oschina.net/u/658505/blog/665164

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值