Error Message Basics in Protractor End-to-End Testing

Recently delved into the world of Angular and now focusing on automating tests. I've created a simple app with a basic form prompting users to input their email. There's a required validator attached to the email field, ensuring that users must enter text. If no text is entered, a message appears below the input field indicating that the form is mandatory. While trying to test this in Protractor, I encountered an error. I believe it's a minor issue in my code. Currently using the latest version of Angular and Jasmine. Any help or advice would be greatly appreciated, as resources for Angular2+ seem scarce.

HTML:

<div *ngIf="!email; else forminfo">
  <form [formGroup]="rForm" (ngSubmit)="submitEmail(rForm.value)">
    <div class="form-container">
      <div class="row columns">

        <h1>{{title}}</h1>

        <label>Email
          <input type="text" formControlName="email">
        </label>
        <div class="alert" *ngIf="!rForm.controls['email'].valid && rForm.controls['email'].touched">{{ titleAlert }}</div>
         <input type="submit" class="button expanded" value="Submit Form" [disabled]="!rForm.valid">

         <button (click)="clickBtn()">test</button>
         <br>
         <p>{{msg}}</p>


      </div>
    </div>
  </form>
</div>

<ng-template #forminfo>
  <div class="form-container">
    <div class="row columns">
      <h1>Thank you for subscribing!</h1>

        <p>Email you have subscribed with: {{ email }}</p> <br> 

    </div>
  </div>
</ng-template>

Component Class

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import {Location} from '@angular/common';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Enter email to subscribe';
  private location: Location;
  rForm: FormGroup;
  submit: any;
  email:string = '';
  titleAlert:string = 'This field is required';
  titleEmail:string = "Email required";
  titleLength: string = 'Min of 7 Characters'
  msg: string;

  constructor(private fb: FormBuilder) {
    this.rForm = fb.group( {
      'email': [null, [Validators.required, Validators.minLength(7),Validators.email]]
    })
  }

  points = 1;



  ngOnInit() {

  }

  clickBtn() {
    this.msg = 'test'
  }

  submitEmail(submit) {
    this.email = submit.email;
  }
}

Object Class

import { browser, by, element } from 'protractor';

export class AppPage {
  navigateTo() {
    return browser.get('/');
  }

  getTitle() {
    return element(by.css('h1')).getText();
  }

  getTestBtn() {
    return element(by.cssContainingText('button', 'test'));
  }
  getErrorMsg() {
    return element(by.cssContainingText('div', 'alert')).getText();

  }

  getInputField() {
    return element(by.cssContainingText('input', 'email'));
  }



}

Spec Class

import { AppPage } from './app.po';

describe('workspace-project App', () => {
  let page: AppPage;

  beforeEach(() => {
    page = new AppPage();

  });

  it('Should display the correct title', () => {
    page.navigateTo();
    expect(page.getTitle()).toEqual('Enter email to subscribe')
  });

  it('should display an input field', () => {
    page.navigateTo();
    expect(page.getInputField()).toBeTruthy();
  })

  it('return an error if text box is left empty', () => {
    page.navigateTo();

    page.getInputField().sendKeys('');
    page.getTestBtn().click();

    expect(page.getErrorMsg()).toBeTruthy();

  })
});

Edit: Got it working by doing this:

   Object Class

  titleAlert = element(by.className('alert');
}
Spec Class

     expect(page.titleAlert.isDisplayed()).toBe(true);

Appreciate your assistance tehbeardedone

Answer №1

Your issue lies in the following code:

getErrorMsg() {
  return element(by.cssContainingText('div', 'alert')).getText();
}

In your component, you have hardcoded the error message text to be:

titleAlert: string = 'This field is required';

You should target the element containing that specific text, not simply any element with alert. Alternatively, you can utilize by.className('alert')

A more effective approach would be to ensure the error message is visible when an invalid form is submitted.

Methods for locating the element:

export class AppPage {
  titleAlert = element(by.className('alert'));

  // or ...

  titleAlert = element(by.cssContainingText('div', 'This field is required'));
}

Subsequently, in your test case, you can simplify this as follows:

it('displays an error if a text box is empty', () => {
  page.navigateTo();

  page.getInputField().sendKeys('');
  page.getTestBtn().click();

  expect(page.titleAlert.isDisplayed()).toBe(true);
});

Additionally, it may be beneficial to refer to the protractor style guide. Specifically focusing on page objects. Refrain from overcomplicating your tests unnecessarily. For instance, instead of using

page.getInputField().sendKeys('');
, opt for page.myInputElement.sendKeys() for simplicity.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Discover the offsetTop value of a child element in React using TypeScript

How can I retrieve the offsetTop of React children in Typescript? Here is an example of my component: export default class FadeIn extends Component { private onScroll = () => { React.Children.forEach(this.props.children, child => { // G ...

The types for Cypress are not being detected by my Angular tsconfig file

I'm facing an issue with my Angular tsconfig not detecting the Cypress 12.3 types. I have tried numerous solutions to resolve this problem, but nothing seems to work, except for the extreme measure of starting the project over, which I think might sol ...

The step-by-step guide to launching a server using Firebase Cloud Functions

After following a tutorial to set up an express server for accessing a MongoDB instance on Google Cloud Platform, I encountered an issue when deploying my Firebase functions. When I run the command firebase deploy --only functions All functions deploy su ...

Phaser 3 game app on iOS generated with Capacitor lacks audio functionality

I have developed a basic test app using Phaser 3 (written in Typescript and transpiled with rollup) and am utilizing Capacitor to convert it into an iOS application on my Mac. This excerpt highlights the key functionality of the app: function preload () { ...

I'm perplexed as to why my array remains empty despite assigning a value to it in my controller. (Just to clarify, I am working with AngularJS, not Angular)

I spent a whole day debugging this issue without any luck. Issue: this.gridOptions.data = this.allTemplatesFromClassificationRepo ; **this.allTemplatesFromClassificationRepo ** remains an empty array. I have already called the activate() function to assig ...

utilizing props to create a navigational link

How can I display a tsx component on a new tab and pass props into the new page? Essentially, I'm looking for the equivalent of this Flutter code: Navigator.push( context, MaterialPageRoute(builder: (context) => Page({title: example, desc: ...

What is the process for causing an Observable that already exists to emit specialized data?

Let's say I have an Observable that was created in the following way: let observable = of(mockData).pipe(delay(5000)); Is there a method to emit a new value to the observers who are currently subscribed to this observable at a later time? I came acr ...

Retrieve the key value pairs exclusively when utilizing the find method on a JSON array in JavaScript

To extract a value from a JSON array, I am utilizing the find method in this manner: let actualElm = this.initialData.find(elm => { if (elm.identifiant == this.actualId) { return elm.country; } }); An issue with using find is that it returns t ...

React Native: Javascript library with typings not recognized as a module

I am currently facing a challenge of integrating the Microsoft Playfab Javascript Library into my React Native app following the recommendations provided here. The library comes with typings and is structured as illustrated here. In my file playfabWrapper. ...

activating serverless.yml for aws-xray

I have been attempting to implement AWS X-Ray for all lambda functions in the following manner: serverless.yml provider: tracing: lambda: true apiGateway: true name: aws runtime: nodejs8.10 stage: ${opt:stage, 'dev'} region: ...

I've encountered an issue where my React website functions correctly on the development server but not on the live website. Where should I start investigating to find the cause of this discrepancy?

I am trying to embed a Datawrapper map using the following code: import InnerHTML from 'dangerously-set-html-content' export function Map1(){ const htmlFile = `<div style="min-height: 374px"> <script type="text ...

Angular/Typescript: develop a factory function that creates objects based on the parent class's properties

I'm currently working on implementing a factory method that can return classes dynamically, and here's my code snippet: getWidget<T extends WidgetBase>(componentName: string): Type<T> { switch (componentName) { default: ...

What is the process for defining a default value for a template-driven form input in Angular 2?

I have a simple input element in my form that requires a default initial value to be set. <input type="number" name="interest_rate" [(ngModel)]="interest_rate"> In my code, I included this.form.controls['interest_rate'].patchValue(this.a ...

Issue encountered in Angular app-routing module.ts: Type error TS2322: The type '"enabled"' cannot be assigned to type 'InitialNavigation | undefined'

When I recently updated my project from Angular 11 to 14, I encountered the following error when running "ng serve". Error: src/app/app-routing.module.ts:107:7 - error TS2322: Type '"enabled"' is not assignable to type 'InitialNavigation | u ...

Typescript - Custom Object type that is always terminated by either a string or a number

Does TypeScript have a way to create a versatile object that can have multiple nested levels but always end with either a string or number property? interface GenericObject { [key: string]: string | number | GenericObject | GenericObject[]; } const obje ...

Clearing a leaflet layer after a click event: Step-by-step guide

When working with my map, I attempt to toggle the layer's selection using a mouse click. Initially, my map looks like this: https://i.sstatic.net/lOI95.png Upon clicking a layer, my goal is to highlight and select it: https://i.sstatic.net/63Rx2.pn ...

Encountering a Runtime Exception while utilizing MapQuest's direction routing feature on Ionic 3

I have successfully generated a map using the Ionic 3 framework, but I encountered a runtime error when attempting to use the L.mapquest.directions().route() function. Here are the imports: <link rel="stylesheet" href="https://unpkg.com/ ...

What is the process of converting the new syntax of SomeFunction() to TypeScript?

When I try to convert a basic JS file to TS while having implicit "any" disabled, I encounter the following error: Error TS7009: When attempting to create a new expression without a constructor signature, it implicitly defaults to an 'any' typ ...

The polyfills.ts file is throwing an error stating that the Element type does not have the property 'msMatchesSelector'

Despite trying the solutions provided on Stack Overflow here and here, I have been unable to resolve the issue. In an attempt to address the error, I created a file called dom.ie.d.ts in the src directory and inserted the following code: interface Element ...

Implement conditional props for a React component by linking them to existing props

In my current project, I am working on a component that has a loading state. The component has an isLoading prop which determines whether the component is currently in a loading state or not: interface CustomImageComponentProps { isLoading: boolean ...