ember-cli-page-object

repository·main·Indexed 43 days ago

https://github.com/san650/ember-cli-page-object

An Ember CLI addon for implementing the Page Object pattern to simplify the construction and maintenance of acceptance and integration tests. It provides blueprints for scaffolding page objects, components, and helpers, along with utilities for element selection (findElement, findOne, findMany) and interaction properties like clickable, fillable, and isVisible. Version 2.1.0 requires Ember.js v3.16+, Ember CLI v2.13+, and Node.js v12+.

Tokens
12.9K
Snippets
45
Records
50
Agent score
54%

What's inside ember-cli-page-object

  1. What is ember-cli-page-object?

    main

    The ember-cli-page-object addon is a tool for creating page objects for acceptance and integration tests in Ember applications. It allows you to model complex pages and components using a declarative syntax, reducing the need for repetitive CSS selectors in your tests and providing a clean, high-level interface for DOM interactions.

    import {
      create,
      visitable,
      fillable,
      clickable,
      text
    } from 'ember-cli-page-object';
    
    const page = create({
      visit: visitable('/'),
    
      username: fillable('#username'),
      password: fillable('#password'),
      submit: clickable('button'),
      error: text('.errors')
    });
    
    test('my awesome test', async function(assert) {
      await page
        .visit()
        .username('admin')
        .password('invalid')
        .submit();
    
      assert.equal(page.error, 'Invalid credentials');
    });
  2. What is the Page Object pattern?

    main
    The Page Object pattern models specific areas of your web application's UI as objects within your test code. This abstraction reduces code duplication in acceptance and integration tests. If the UI changes, you only need to update the Page Object in one place rather than updating every individual test case.
  3. Manage component scopes and nesting

    main

    The scope attribute defines the CSS selector that encloses a component. By default, nested components inherit the parent's scope to build a specific selector (e.g., .parent .child).

    If you need a nested component to ignore the parent's scope and use an absolute selector, set resetScope: true in its definition.

    const form = create({
      scope: '.my-form',
    
      dialog: {
        scope: '.some-dialog',
        resetScope: true
      }
    });
    
    // dialog will be searched for using '.some-dialog' instead of '.my-form .some-dialog'
  4. Use Attributes and Actions

    main

    Attributes are declarative wrappers around DOM operations. They can be used to query state (getters) or perform operations (actions).

    • Attributes: Used to query values like text() or value(). You can pass a selector to an attribute to add specificity beyond the component's scope.
    • Actions: Special attributes that perform asynchronous DOM operations. They return a Promise-like chainable page object node, allowing you to chain multiple operations in a single await statement.

    Commonly used default attributes include click, fillIn, isVisible, isPresent, text, and value.

    import { create, fillable, triggerable } from 'ember-cli-page-object';
    
    const form = create({
      scope: 'form.search-form',
    
      fillIn: fillable('input[type="search"]'),
      submit: triggerable('submit')
    });
    
    // Actions are chainable
    await form
      .fillIn('some text')
      .submit();
  5. How to create a page object with ember-cli-page-object

    main

    To create a page object, use the create function and define your page elements using specialized helpers. These helpers define how to interact with specific DOM elements:

    • visitable(path): Defines a method to navigate to a specific URL.
    • fillable(selector): Defines an element that can be filled with text (e.g., an input).
    • clickable(selector): Defines an element that can be clicked (e.g., a button).
    • text(selector): Defines an element used to retrieve text content.

    Once defined, the page object methods can be chained together in your tests to perform sequences of actions.

    import {
      create,
      visitable,
      fillable,
      clickable,
      text
    } from 'ember-cli-page-object';
    
    const page = create({
      visit: visitable('/'),
    
      username: fillable('#username'),
      password: fillable('#password'),
      submit: clickable('button'),
      error: text('.errors')
    });
    
    test('my awesome test', async function(assert) {
      await page
        .visit()
        .username('admin')
        .password('invalid')
        .submit();
    
      assert.equal(page.error, 'Invalid credentials');
    });
  6. Define and create Page Object components

    main

    Components are functional fragments of the DOM described using plain objects. You define a component by specifying its scope (a CSS selector) and its attributes or methods. Component instances are created using the create function.

    For complex interfaces, compose simpler component definitions into larger ones. When a component is nested, its selector is calculated by combining the parent's scope with the child's scope.

    import { create, clickable, fillable } from 'ember-cli-page-object';
    
    const FormDefinition = {
      scope: '.awesome-form',
    
      firstName: fillable('#firstName'),
      lastName: fillable('#lastName'),
      submit: clickable('button')
    };
    
    const form = create(FormDefinition);
    
    await form
      .firstName('John')
      .lastName('Doe')
      .submit();
  7. Migrate from ember-cli-page-object v1.x to v2.x

    main

    Upgrading to ember-cli-page-object v2.x involves several breaking changes aimed at supporting modern Ember versions (4+) and Embroider.

    Key Changes

    • API Cleanup: Legacy APIs have been removed to simplify internals.
    • Test Helper Requirements: Support for the old Ember moduleFor flavored tests has been completely removed. If you have already migrated to @ember/test-helpers, you likely won't need additional changes.
    • Async/Await: If your codebase uses page object actions that are not async/await aware, you may need to refactor them. You can use the explicit-async codemod to assist with this.
    • Dependency Requirement: To support Embroider, this version requires ember-auto-import@^2.0.0. Ensure your project has this version installed.

    Migration Steps

    1. Check Test Helpers: Ensure you are using @ember/test-helpers instead of moduleFor.
    2. Handle Async Actions: If encountering issues with async actions, run the explicit-async codemod:
      npx ember-page-object-codemod
    3. Verify ember-auto-import: Ensure ember-auto-import is at version ^2.0.0 or higher.
    npx ember-page-object-codemod
  8. Create and use a Page Object

    main

    A Page Object represents a complete route/template in your application. It is composed of various page-object-components and can include attributes like visitable for navigation and collection for lists of elements.

    Unlike components, Page Objects are typically exported as an instance created via create(), allowing them to be imported and used directly in acceptance tests.

    You can also define native asynchronous methods on a Page Object to provide high-level APIs that orchestrate multiple component interactions.

    $ ember generate page-object search-page
  9. Extend components with custom functions and getters

    main

    You can add native JavaScript functions and getters to your component definitions to create higher-level, domain-specific APIs for your tests. This is useful for grouping multiple low-level interactions into a single logical step or transforming data (e.g., mapping a collection of elements to an array of strings).

    import { collection } from 'ember-cli-page-object';
    
    const MyForm = {
      errors: collection('ul.errors > li'),
    
      title: { scope: '#firstName' },
      description: { scope: '#lastName' },
      submitButton: { scope: 'button' },
    
      async submit(data) {
        await this.title.fillIn(data.username);
        await this.description.fillIn(data.password);
        return this.submitButton.click();
      }
    
      get errorMessages() {
        return this.errors.map((e) => e.text);
      }
    };
  10. Create a Page Object Component

    main

    A Page Object Component is the primary building block of the library. It consists of a scope, attributes, custom methods, and nested components. You can generate a component definition using the ember generate page-object-component command.

    To define a component, you specify its CSS scope and then define its attributes (like text inputs or buttons). You can use triggerable to define action attributes that trigger DOM events.

    $ ember generate page-object-component search-form
  11. Use blueprints to generate Page Objects and related files

    main

    The addon provides blueprints to scaffold common Page Object patterns. You can use the ember generate command to create these files.

    Available Blueprints

    • page-object: Creates a new page object.
    • page-object-component: Creates a new component to be used in a page object.
    • page-object-helper: Creates a new helper to be used in a page object.

    Example: Generating a Page Object

    To create a new page object named users, run:

    $ ember generate page-object users

    This will create the file at tests/pages/users.js.

  12. Install ember-cli-page-object

    main

    You can install the addon using the Ember CLI install command or by adding the NPM package directly to your development dependencies.

    Using Ember CLI

    $ ember install ember-cli-page-object

    Using NPM

    $ npm install --save-dev ember-cli-page-object