Commands, Queries and Assertions (Test Automation)
Learn Commands, Queries and Assertions (Test Automation) step by step with clear examples and exercises.
Why This Matters
Understanding the fundamentals of commands, queries, and assertions in test automation is crucial for writing efficient and reliable test scripts. By mastering these concepts, you'll be able to create robust test suites that can help reduce human error, accelerate testing processes, ensure consistency across multiple runs, and facilitate regression testing.
Prerequisites
To fully grasp the core concept of test automation with commands, queries, and assertions, it is essential to have:
- A solid understanding of JavaScript programming language concepts and syntax. Familiarity with control structures (e.g., loops, conditionals), functions, objects, and ES6 features like arrow functions, promises, and async/await will be beneficial.
- Familiarity with web development fundamentals, including HTML, CSS, and DOM manipulation. Understanding how the browser renders web pages and interacts with them is crucial for writing effective test scripts.
- Experience working with one or more test automation frameworks like Selenium, Cypress, or Playwright. Familiarity with their APIs, configuration options, and best practices will help you write efficient and maintainable test scripts.
- Basic knowledge of browser development tools (DevTools) for debugging and inspecting elements during test execution. This includes understanding how to navigate the DOM tree, view network requests, and manipulate CSS styles.
- Familiarity with version control systems (e.g., Git) to manage test scripts and collaborate effectively with other developers. Understanding basic Git commands like
git init,git add,git commit, andgit pushwill help you work efficiently in a team environment. - Knowledge of testing methodologies such as BDD (Behavior-Driven Development) and TDD (Test-Driven Development). These methodologies emphasize clear, concise test descriptions, making tests easier to understand and maintain over time.
- Understanding the importance of maintaining clean, well-organized code that is easy to read and modify. This includes using meaningful names for elements, functions, and variables; keeping tests modular and self-contained; minimizing the use of global variables; and implementing proper error handling and logging.
Core Concept
Commands
Commands are actions executed by the test script on the Application Under Test (AUT). They simulate user interactions, such as clicking buttons, filling out forms, or navigating between pages. Commands are essential for controlling the AUT and verifying its behavior during tests.
// Example Selenium command to navigate to a URL
const webDriver = new webdriver.Builder().forBrowser('chrome').build();
webDriver.get('https://www.example.com');
// Example Cypress command to click a button
cy.visit('https://www.example.com');
cy.get('#submitButton').click();
Navigation Commands
Navigation commands help control the flow of the test by navigating between pages or opening new tabs/windows. Examples include:
webDriver.navigate().to(url)(Selenium)cy.visit(url)(Cypress)page.goto(url)(Playwright)
Interaction Commands
Interaction commands help simulate user interactions with the AUT, such as clicking buttons, filling out forms, or hovering over elements. Examples include:
webDriver.findElement(By.id('elementId')).click()(Selenium)cy.get('#elementId').type('text')(Cypress)page.locator('#elementId').click()(Playwright)
Assertion Commands
Assertion commands help verify that the AUT behaves as expected during test execution. They compare the actual state of the AUT with the expected state and report a failure if they do not match. Examples include:
expect(webDriver.findElement(By.id('elementId')).getText()).toEqual('Expected Text')(Selenium)cy.get('#elementId').should('contain', 'Expected Text')(Cypress)page.locator('#elementId').textContent().shouldContain('Expected Text')(Playwright)
Queries
Queries are used to locate UI elements within the AUT for interaction. They can be based on various attributes like ID, class name, or CSS selector. Queries help test scripts interact with specific elements during test execution.
// Example Selenium query to find an element by ID
const element = webDriver.findElement(webdriver.By.id('elementId'));
// Example Cypress query to find an element by CSS selector
cy.get('.css-selector');
Locator Strategies
Different locator strategies can be used depending on the availability and uniqueness of attributes for the UI elements you want to interact with. Some common strategies include:
- ID (e.g.,
webdriver.By.id('elementId'),cy.getElementById('elementId'),page.locator('#elementId')) - Class Name (e.g.,
webdriver.By.className('className'),cy.get('.className'),page.locator('.className')) - CSS Selector (e.g.,
webdriver.By.cssSelector('css-selector'),cy.contains('text').within(cy.get('parent-selector')),page.locator('css-selector')) - XPath (e.g.,
webdriver.By.xpath('xpath-expression'),cy.xpath('xpath-expression'),page.locator('xpath-expression'))
Assertions
Assertions are used to verify that the AUT behaves as expected during test execution. They compare the actual state of the AUT with the expected state and report a failure if they do not match. Assertions help ensure that tests are accurate and reliable, providing valuable feedback on the AUT's behavior.
// Example Selenium assertion to verify that a specific text is displayed on the page
webDriver.findElement(webdriver.By.id('message')).getText().then(text => {
expect(text).toEqual('Expected Text');
});
// Example Cypress assertion to verify that an element contains specific text
cy.get('#elementId').should('contain', 'Expected Text');
Assertion Libraries
Different libraries can be used for writing assertions in JavaScript, such as:
- Jest (https://jestjs.io/) - A popular testing framework for JavaScript that includes built-in assertion functions like
expect(value).toEqual(expected). - Chai (http://chaijs.com/) - A flexible assertion library for JavaScript with a BDD-style syntax, such as
assert.equal(actual, expected)orexpect(actual).to.equal(expected). - Mocha (https://mochajs.org/) - A feature-rich testing framework for JavaScript that can be used in combination with Chai or other assertion libraries.
Worked Example
Let's create a simple test script using Selenium and JavaScript to automate the login process of a web application:
- Set up the WebDriver instance, navigate to the login page, and find the username input field.
- Enter the correct username and find the password input field, entering the correct password.
- Find the login button and click it.
- Assert that the user is successfully logged in by verifying that the welcome message is displayed.
const {Builder, By, Key} = require('selenium-webdriver');
(async function example() {
let driver = await new Builder().forBrowser('chrome').build();
try {
await driver.get('https://www.example.com/login');
// Find username input field and enter the correct username
const usernameField = await driver.findElement(By.name('username'));
await usernameField.sendKeys('correctUsername');
// Find password input field and enter the correct password
const passwordField = await driver.findElement(By.name('password'));
await passwordField.sendKeys('correctPassword', Key.RETURN);
// Find login button and click it
const loginButton = await driver.findElement(By.id('loginButton'));
await loginButton.click();
// Assert that the user is successfully logged in by verifying that the welcome message is displayed
const welcomeMessage = await driver.findElement(By.id('welcomeMessage'));
let text = await welcomeMessage.getText();
expect(text).toEqual('Welcome, correctUsername');
} catch (error) {
console.error(`Error: ${error}`);
} finally {
await driver.quit();
}
})();
Common Mistakes
- Incorrect locator: Using an incorrect or outdated locator can lead to test failures due to the inability to locate the intended UI element. To avoid this, use meaningful and unique locators, and update them when changes are made to the AUT.
- Improper waits: Failing to properly handle asynchronous operations such as page loads, AJAX calls, and user interactions can result in test failures. Use explicit or implicit waits to ensure that elements are available before interacting with them.
- Hardcoded values: Hardcoding sensitive information like passwords or API keys can pose a security risk. Store these values securely (e.g., using environment variables or configuration files) and avoid committing them to version control systems.
- Lack of assertions: Neglecting to include assertions to verify the expected state of the AUT can lead to tests that pass even when they should fail. Always validate the behavior of the AUT after performing actions to ensure accuracy.
- Ignoring browser-specific issues: Different browsers may behave differently, and test scripts need to be designed to handle these differences. Use cross-browser testing tools or write separate test suites for each browser if necessary.
- Inefficient code: Writing inefficient or poorly optimized code can result in slower test execution times and increased maintenance efforts. Refactor your code when possible to improve performance and maintainability.
- Lack of error handling: Failing to properly handle errors can lead to unexpected behavior during test execution, making it difficult to identify and resolve issues. Implement try-catch blocks or other error handling mechanisms to handle exceptions gracefully.
- Test brittleness: Test scripts may become brittle over time due to changes in the AUT. Use techniques like page object patterns, abstraction layers, and data-driven testing to make your tests more resilient to such changes.
- Overemphasis on test quantity over quality: Writing too many tests without considering their value or maintainability can lead to a large, unwieldy test suite that is difficult to manage and maintain. Focus on writing high-quality, well-designed tests that cover critical functionality and are easy to understand and modify.
- Ignoring test maintenance: Test suites require regular maintenance to ensure they continue to function correctly as the AUT evolves. Allocate time for periodic reviews and updates of your test suite to maintain its effectiveness.
Practice Questions
- Write a Selenium command to fill out a form with the following details:
- First name: John
- Last name: Doe
- Email: john.doe@example.com
- Password: password123
const {Builder, By, Key} = require('selenium-webdriver');
(async function example() {
let driver = await new Builder().forBrowser('chrome').build();
try {
await driver.get('https://www.example.com/register');
// Find first name input field and enter the correct value
const firstNameField = await driver.findElement(By.name('firstName'));
await firstNameField.sendKeys('John');
// Find last name input field and enter the correct value
const lastNameField = await driver.findElement(By.name('lastName'));
await lastNameField.sendKeys('Doe');
// Find email input field and enter the correct value
const emailField = await driver.findElement(By.name('email'));
await emailField.sendKeys('john.doe@example.com');
// Find password input field and enter the correct value
const passwordField = await driver.findElement(By.name('password'));
await passwordField.sendKeys('password123', Key.RETURN);
} catch (error) {
console.error(`Error: ${error}`);
} finally {
await driver.quit();
}
})();
- Write a Cypress query to locate an element with the class
btnand a data-id attribute ofsubmit.
cy.get('.btn[data-id="submit"]');
FAQ
- Why do we need test automation?
Test automation helps reduce human error during repetitive tasks, accelerate testing processes by running tests quickly and consistently, ensure consistency across multiple runs, facilitate regression testing, and enable teams to maintain high-quality software.
- What are the benefits of using commands, queries, and assertions in test automation?
Using commands, queries, and assertions in test automation allows for efficient control over the Application Under Test (AUT), accurate verification of its behavior, and easy maintenance of test scripts.
- How can I improve the performance of my test scripts?
To improve the performance of your test scripts, refactor your code to remove any unnecessary steps, optimize wait times,