
Protractor is a popular end-to-end test framework that lets you test your Angular application on a real browser simulating the browser interactions just the way that a real user would interact with it. End-to-end tests are designed to ensure that the application behaves as expected from a user's perspective. Moreover, the tests are not concerned about the actual code implementation.
Protractor runs on top of the popular Selenium WebDriver, which is an API for browser automation and testing. In addition to the features provided by Selenium WebDriver, Protractor offers locators and methods for capturing the UI components of the Angular application.
In this tutorial, you will learn about:
Doesn't that sound exciting? However, first things first.
If you've been using Angular-CLI, you might know that by default, it comes shipped with two frameworks for testing. They are:
The apparent difference between the two is that the former is used to test the logic of the components and services, while the latter is used to ensure that the high-level functionality (which involves the UI elements) of the application works as expected.
If you are new to testing in Angular, I'd recommend reading the Testing Components in Angular Using Jasmine series to get a better idea of where to draw the line.
In the former's case, you can leverage the power of Angular testing utilities and Jasmine to write not just unit tests for components and services, but basic UI tests also. However, if you need to test the front-end functionality of your application from start to end, Protractor is the way to go. Protractor's API combined with design patterns such as page objects make it easier to write tests that are more readable. Here's an example to get things rolling.
/*
1. It should have a create Paste button
2. Clicking the button should bring up a modal window
*/
it('should have a Create Paste button and modal window', () => {
expect(addPastePage.isCreateButtonPresent()).toBeTruthy("The button should exist");
expect(addPastePage.isCreatePasteModalPresent()).toBeFalsy("The modal window shouldn't exist, not yet!");
addPastePage.clickCreateButton();
expect(addPastePage.isCreatePasteModalPresent()).toBeTruthy("The modal window should appear now");
});Setting up Protractor is easy if you are using Angular-CLI to generate your project. The directory structure created by ng new is as follows.
. ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json ├── karma.conf.js ├── package.json ├── package-lock.json ├── protractor.conf.js ├── README.md ├── src │ ├── app │ ├── assets │ ├── environments │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts ├── tsconfig.json └── tslint.json 5 directories, 19 files
The default project template created by Protractor depends on two files to run the tests: the spec files that reside inside the e2e directory and the configuration file (protractor.conf.js). Let's see how configurable protractor.conf.js is:
/* Path: protractor.conf.ts*/
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};
If you are ok with running the test on Chrome web browser, you can leave this as is and skip the rest of this section.
The directConnect: true lets Protractor connect directly to the browser drivers. However, at the moment of writing this tutorial, Chrome is the only supported browser. If you need multi-browser support or run a browser other than Chrome, you will have to set up Selenium standalone server. The steps are as follows.
Install Protractor globally using npm:
npm install -g protractor
This installs the command-line tool for webdriver-manager along with that of protractor. Now update the webdriver-manager to use the latest binaries, and then start the Selenium standalone server.
webdriver-manager update webdriver-manager start
Finally, set the directConnect: false and add the seleniumAddress property as follows:
capabilities: {
'browserName': 'firefox'
},
directConnect: false,
baseUrl: 'http://localhost:4200/',
seleniumAddress: 'http://localhost:4444/wd/hub',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},The config file on GitHub provides more information about the configuration options available on Protractor. I will be using the default options for this tutorial.
ng e2e is the only command you need to start running the tests if you are using Angular-CLI. If the tests appear to be slow, it's because Angular has to compile the code every time you run ng e2e. If you want to speed it up a bit, here's what you should do. Serve the application using ng serve.
Then fire up a new console tab and run:
ng e2e -s false
The tests should load faster now.
We will be writing E2E tests for a basic Pastebin application. Clone the project from the GitHub repo.
Both the versions, the starter version (the one without the tests) and the final version (the one with the tests), are available on separate branches. Clone the starter branch for now. Optionally, serve the project and go through the code to get acquainted with the application at hand.
Let's describe our Pastebin application briefly. The application will initially load a list of pastes (retrieved from a mock server) into a table. Each row in the table will have a View Paste button which, when clicked on, opens up a bootstrap modal window. The modal window displays the paste data with options to edit and delete the paste. Towards the end of the table, there is a Create Paste button which can be used to add new pastes.

The rest of the tutorial is dedicated to writing Protractor tests in Angular.
The spec file, ending with .e2e-spec.ts, will host the actual tests for our application. We will be placing all the test specs inside the e2e directory since that's the place we've configured Protractor to look for the specs.
There are two things you need to consider while writing Protractor tests:
Create a new file called test.e2e-spec.ts with the following code to get started.
/* Path: e2e/test.e2e-spec.ts */
import { browser, by, element } from 'protractor';
describe('Protractor Demo', () => {
beforeEach(() => {
//The code here will get executed before each it block is called
//browser.get('/');
});
it('should display the name of the application',() => {
/*Expectations accept parameters that will be matched with the real value
using Jasmine's matcher functions. eg. toEqual(),toContain(), toBe(), toBeTruthy() etc. */
expect("Pastebin Application").toEqual("Pastebin Application");
});
it('should click the create Paste button',() => {
//spec goes here
});
});This depicts how our tests will be organized inside the spec file using Jasmine's syntax. describe(), beforeEach() and it() are global Jasmine functions.
Jasmine has a great syntax for writing tests, and it works just as well with Protractor. If you are new to Jasmine, I would recommend going through Jasmine's GitHub page first.
The describe block is used to divide the tests into logical test suites. Each describe block (or test suite) can have multiple it blocks (or test specs). The actual tests are defined inside the test specs.
"Why should I structure my tests this way?" you may ask. A test suite can be used to logically describe a particular feature of your application. For instance, all the specs concerned with the Pastebin component should ideally be covered inside a describe block titled Pastebin Page. Although this may result in tests that are redundant, your tests will be more readable and maintainable.
A describe block can have a beforeEach() method which will be executed once, before each spec in that block. So, if you need the browser to navigate to a URL before each test, placing the code for navigation inside beforeEach() is the right thing to do.
Expect statements, which accept a value, are chained with some matcher functions. Both the real and the expected values are compared, and a boolean is returned which determines whether the test fails or not.
Now, let's put some flesh on it.
/* Path: e2e/test.e2e-spec.ts */
import { browser, by, element } from 'protractor';
describe('Protractor Demo', () => {
beforeEach(() => {
browser.get('/');
});
it('should display the name of the application',() => {
expect(element(by.css('.pastebin')).getText()).toContain('Pastebin Application');
});
it('create Paste button should work',() => {
expect(element(by.id('source-modal')).isPresent()).toBeFalsy("The modal window shouldn't appear right now ");
element(by.buttonText('create Paste')).click();
expect(element(by.id('source-modal')).isPresent()).toBeTruthy('The modal window should appear now');
});
});browser.get('/') and element(by.css('.pastebin')).getText() are part of the Protractor API. Let's get our hands dirty and jump right into what Protractor has to offer.
The prominent components exported by Protractor API are listed below.
browser(): You should call browser() for all the browser-level operations such as navigation, debugging, etc. element(): This is used to look up an element in the DOM based on a search condition or a chain of conditions. It returns an ElementFinder object, and you can perform actions such as getText() or click() on them.element.all(): This is used to look for an array of elements that match some chain of conditions. It returns an ElementArrayFinder object. All the actions that can be performed on ElementFinder can be performed on ElementArrayFinder also.Since we will be using locators very often, here are some of the commonly used locators.
by.css('selector-name'): This is by far the commonly used locator for finding an element based on the name of the CSS selector.by.name('name-value'): Locates an element with a matching value for the name attribute.by.buttonText('button-value'): Locates a button element or an array of button elements based on the inner text. Note: The locators by.model, by.binding and by.repeater do not work with Angular 2+ applications at the time of writing this tutorial. Use the CSS-based locators instead.
Let's write more tests for our Pastebin application.
it('should accept and save input values', () => {
element(by.buttonText('create Paste')).click();
//send input values to the form using sendKeys
element(by.name('title')).sendKeys('Hello world in Ruby');
element(by.name('language')).element(by.cssContainingText('option', 'Ruby')).click();
element(by.name('paste')).sendKeys("puts 'Hello world';");
element(by.buttonText('Save')).click();
//expect the table to contain the new paste
const lastRow = element.all(by.tagName('tr')).last();
expect(lastRow.getText()).toContain("Hello world in Ruby");
});The code above works, and you can verify that yourself. However, wouldn't you feel more comfortable writing tests without the Protractor-specific vocabulary in your spec file? Here's what I am talking about:
it('should have an Create Paste button and modal window', () => {
expect(addPastePage.isCreateButtonPresent()).toBeTruthy("The button should exist");
expect(addPastePage.isCreatePasteModalPresent()).toBeFalsy("The modal window shouldn't appear, not yet!");
addPastePage.clickCreateButton();
expect(addPastePage.isCreatePasteModalPresent()).toBeTruthy("The modal window should appear now");
});
it('should accept and save input values', () => {
addPastePage.clickCreateButton();
//Input field should be empty initially
const emptyInputValues = ["","",""];
expect(addPastePage.getInputPasteValues()).toEqual(emptyInputValues);
//Now update the input fields
addPastePage.addNewPaste();
addPastePage.clickSaveButton();
expect(addPastePage.isCreatePasteModalPresent()).toBeFalsy("The modal window should be gone");
expect(mainPage.getLastRowData()).toContain("Hello World in Ruby");
});The specs appear more straightforward without the extra Protractor baggage. How did I do that? Let me introduce you to Page Objects.
Page Object is a design pattern which is popular in the test automation circles. A page object models a page or part of an application using an object-oriented class. All the objects (that are relevant to our tests) like text, headings, tables, buttons, and links can be captured in a page object. We can then import these page objects into the spec file and invoke their methods. This reduces code duplication and makes maintenance of code easier.
Create a directory named page-objects and add a new file inside it called pastebin.po.ts. All the objects concerned with the Pastebin component will be captured here. As previously mentioned, we divided the whole app into three different components, and each component will have a page object dedicated to it. The naming scheme .po.ts is purely conventional, and you can name it anything you want.
Here is a blueprint of the page we are testing.

Here is the code.
/* Path e2e/page-objects/pastebin.po.ts*/
import { browser, by, element, promise, ElementFinder, ElementArrayFinder } from 'protractor';
export class Pastebin extends Base {
navigateToHome():promise.Promise<any> {
return browser.get('/');
}
getPastebin():ElementFinder {
return element(by.css('.pastebin'));
}
/* Pastebin Heading */
getPastebinHeading(): promise.Promise<string> {
return this.getPastebin().element(by.css("h2")).getText();
}
/*Table Data */
getTable():ElementFinder {
return this.getTable().element(by.css('table'));
}
getTableHeader(): promise.Promise<string> {
return this.getPastebin().all(by.tagName('tr')).get(0).getText();
}
getTableRow(): ElementArrayFinder {
return this.getPastebin().all(by.tagName('tr'));
}
getFirstRowData(): promise.Promise<string> {
return this.getTableRow().get(1).getText();
}
getLastRowData(): promise.Promise<string> {
return this.getTableRow().last().getText();
}
/*app-add-paste tag*/
getAddPasteTag(): ElementFinder {
return this.getPastebin().element(by.tagName('app-add-paste'));
}
isAddPasteTagPresent(): promise.Promise<boolean> {
return this.getAddPasteTag().isPresent();
}
}Let's go over what we've learned thus far. Protractor's API returns objects, and we've encountered three types of objects thus far. They are:
In short, element() returns an ElementFinder, and element().all returns an ElementArrayFinder. You can use the locators (by.css, by.tagName, etc.) to find the location of the element in the DOM and pass it to element() or element.all().
ElementFinder and ElementArrayFinder can then be chained with actions, such as isPresent(), getText(), click(), etc. These methods return a promise that gets resolved when that particular action has been completed.
The reason why we don't have a chain of then()s in our test is because Protractor takes care of it internally. The tests appear to be synchronous even though they are not; therefore, the end result is a linear coding experience. However, I recommend using async/await syntax to ensure that the code is future proof.
You can chain multiple ElementFinder objects, as shown below. This is particularly helpful if the DOM has multiple selectors of the same name and we need to capture the right one.
getTable():ElementFinder {
return this.getPastebin().element(by.css('table'));
}Now that we have the code for the page object ready, let's import it into our spec. Here's the code for our initial tests.
/* Path: e2e/mainPage.e2e-spec.ts */
import { Pastebin } from './page-objects/pastebin.po';
import { browser, protractor } from 'protractor';
/* Scenarios to be Tested
1. Pastebin Page should display a heading with text Pastebin Application
2. It should have a table header
3. The table should have rows
4. app-add-paste tag should exist
*/
describe('Pastebin Page', () => {
const mainPage: Pastebin = new Pastebin();
beforeEach(() => {
mainPage.navigateToHome();
});
it('should display the heading Pastebin Application', () => {
expect(mainPage.getPastebinHeading()).toEqual("Pastebin Application");
});
it('should have a table header', () => {
expect(mainPage.getTableHeader()).toContain("id Title Language Code");
})
it('table should have at least one row', () => {
expect(mainPage.getFirstRowData()).toContain("Hello world");
})
it('should have the app-add-paste tag', () => {
expect(mainPage.isAddPasteTagPresent()).toBeTruthy();
})
});Tests should be organized in such a way that the overall structure appears meaningful and straightforward. Here are some opinionated guidelines that you should keep in mind while organizing E2E tests.
navigateToHome()), create a base page object. Other page models can inherit from the base page model. Following the guidelines above, here's what the page object hierarchy and the file organization should look like.

We've already covered pastebin.po.ts and mainPage.e2e-spec.ts. Here are the rest of the files.
/* path: e2e/page-objects/base.po.ts */
import { browser, by, element, promise, ElementFinder, ElementArrayFinder } from 'protractor';
export class Base {
/* Navigational methods */
navigateToHome():promise.Promise<any> {
return browser.get('/');
}
navigateToAbout():promise.Promise<any> {
return browser.get('/about');
}
navigateToContact():promise.Promise<any> {
return browser.get('/contact');
}
/* Mock data for creating a new Paste and editing existing paste */
getMockPaste(): any {
let paste: any = { title: "Something here",language: "Ruby",paste: "Test"}
return paste;
}
getEditedMockPaste(): any {
let paste: any = { title: "Paste 2", language: "JavaScript", paste: "Test2" }
return paste;
}
/* Methods shared by addPaste and viewPaste */
getInputTitle():ElementFinder {
return element(by.name("title"));
}
getInputLanguage(): ElementFinder {
return element(by.name("language"));
}
getInputPaste(): ElementFinder {
return element(by.name("paste"));
}
}
/* Path: e2e/page-objects/add-paste.po.ts */
import { browser, by, element, promise, ElementFinder, ElementArrayFinder } from 'protractor';
import { Base } from './base.po';
export class AddPaste extends Base {
getAddPaste():ElementFinder {
return element(by.tagName('app-add-paste'));
}
/* Create Paste button */
getCreateButton(): ElementFinder {
return this.getAddPaste().element(by.buttonText("create Paste"));
}
isCreateButtonPresent() : promise.Promise<boolean> {
return this.getCreateButton().isPresent();
}
clickCreateButton(): promise.Promise<void> {
return this.getCreateButton().click();
}
/*Create Paste Modal */
getCreatePasteModal(): ElementFinder {
return this.getAddPaste().element(by.id("source-modal"));
}
isCreatePasteModalPresent() : promise.Promise<boolean> {
return this.getCreatePasteModal().isPresent();
}
/*Save button */
getSaveButton(): ElementFinder {
return this.getAddPaste().element(by.buttonText("Save"));
}
clickSaveButton():promise.Promise<void> {
return this.getSaveButton().click();
}
/*Close button */
getCloseButton(): ElementFinder {
return this.getAddPaste().element(by.buttonText("Close"));
}
clickCloseButton():promise.Promise<void> {
return this.getCloseButton().click();
}
/* Get Input Paste values from the Modal window */
getInputPasteValues(): Promise<string[]> {
let inputTitle, inputLanguage, inputPaste;
// Return the input values after the promise is resolved
// Note that this.getInputTitle().getText doesn't work
// Use getAttribute('value') instead
return Promise.all([this.getInputTitle().getAttribute("value"), this.getInputLanguage().getAttribute("value"), this.getInputPaste().getAttribute("value")])
.then( (values) => {
return values;
});
}
/* Add a new Paste */
addNewPaste():any {
let newPaste: any = this.getMockPaste();
//Send input values
this.getInputTitle().sendKeys(newPaste.title);
this.getInputLanguage()
.element(by.cssContainingText('option', newPaste.language)).click();
this.getInputPaste().sendKeys(newPaste.paste);
//Convert the paste object into an array
return Object.keys(newPaste).map(key => newPaste[key]);
}
}/* Path: e2e/addNewPaste.e2e-spec.ts */
import { Pastebin } from './page-objects/pastebin.po';
import { AddPaste } from './page-objects/add-paste.po';
import { browser, protractor } from 'protractor';
/* Scenarios to be Tested
1. AddPaste Page should have a button when clicked on should present a modal window
2. The modal window should accept the new values and save them
4. The saved data should appear in the MainPage
3. Close button should work
*/
describe('Add-New-Paste page', () => {
const addPastePage: AddPaste = new AddPaste();
const mainPage: Pastebin = new Pastebin();
beforeEach(() => {
addPastePage.navigateToHome();
});
it('should have an Create Paste button and modal window', () => {
expect(addPastePage.isCreateButtonPresent()).toBeTruthy("The button should exist");
expect(addPastePage.isCreatePasteModalPresent()).toBeFalsy("The modal window shouldn't appear, not yet!");
addPastePage.clickCreateButton();
expect(addPastePage.isCreatePasteModalPresent()).toBeTruthy("The modal window should appear now");
});
it("should accept and save input values", () => {
addPastePage.clickCreateButton();
const emptyInputValues = ["","",""];
expect(addPastePage.getInputPasteValues()).toEqual(emptyInputValues);
const newInputValues = addPastePage.addNewPaste();
expect(addPastePage.getInputPasteValues()).toEqual(newInputValues);
addPastePage.clickSaveButton();
expect(addPastePage.isCreatePasteModalPresent()).toBeFalsy("The modal window should be gone");
expect(mainPage.getLastRowData()).toContain("Something here");
});
it("close button should work", () => {
addPastePage.clickCreateButton();
addPastePage.clickCloseButton();
expect(addPastePage.isCreatePasteModalPresent()).toBeFalsy("The modal window should be gone");
});
});
There are a couple of things missing, though: the tests for the View Paste button and the modal window that pops up after clicking the button. I am going to leave this as an exercise for you. However, I will drop you a hint.
The structure of the page objects and the specs for the ViewPastePage are similar to that of the AddPastePage.

Here are the scenarios that you need to test:
Try to stick to the guidelines wherever possible. If you're in doubt, switch to the final branch to see the final draft of the code.
So there you have it. In this article, we've covered writing end-to-end tests for our Angular application using Protractor. We started off with a discussion about unit tests vs. e2e tests, and then we learned about setting up, configuring and running Protractor. The rest of the tutorial concentrated on writing actual tests for the demo Pastebin application.
Please let me know your thoughts and experiences about writing tests using Protractor or writing tests for Angular in general. I would love to hear them. Thanks for reading!
The Best Small Business Web Designs by DesignRush
/
2Create Modern Vue Apps Using Create-Vue and Vite
/
9How to Fix the “There Has Been a Critical Error in Your Website” Error in WordPress
/
3How To Fix The “There Has Been A Critical Error in Your Website” Error in WordPress
How to Create a Privacy Policy Page in WordPress
/
7WordPress Website Maintenance Guide For Beginners
/
8How Long Does It Take to Learn JavaScript?
/
-1How Long Does it Take to Learn JavaScript
/
1The Best Way to Deep Copy an Object in JavaScript
/
-1
4
-5Adding and Removing Elements From Arrays in JavaScript
/
-1Create a JavaScript AJAX Post Request: With and Without jQuery
/
85 Real-Life Uses for the JavaScript reduce() Method
/
-9How to Enable or Disable a Button With JavaScript: jQuery vs. Vanilla
/
4How to Enable or Disable a Button With JavaScript: jQuery vs Vanilla
/
-5Confirm Yes or No With JavaScript
/
-4How to Change the URL in JavaScript: Redirecting
/
-127 Best Tab and Accordion Widget Plugins for WordPress (Free & Premium)
/
1421 Best Tab and Accordion Widget Plugins for WordPress (Free & Premium)
/
-1030 HTML Best Practices for Beginners
/
-731 Best WordPress Calendar Plugins and Widgets (With 5 Free Plugins)
/
125 Ridiculously Impressive HTML5 Canvas Experiments
/
-3
1How to Implement Email Verification for New Members
/
2How to Create a Simple Web-Based Chat Application
/
630 Popular WordPress User Interface Elements
/
-2Top 18 Best Practices for Writing Super Readable Code
/
1Best Affiliate WooCommerce Plugins Compared
/
-1118 Best WordPress Star Rating Plugins
/
1410+ Best WordPress Twitter Widgets
/
220+ Best WordPress Booking and Reservation Plugins
/
4Working With Tables in React: Part Two
/
-3Best CSS Animations and Effects on CodeCanyon
/
-1730 CSS Best Practices for Beginners
/
3How to Create a Custom WordPress Plugin From Scratch
/
210 Best Responsive HTML5 Sliders for Images and Text… and 3 Free Options
/
-616 Best Tab and Accordion Widget Plugins for WordPress
/
-618 Best WordPress Membership Plugins and 5 Free Plugins
/
325 Best WooCommerce Plugins for Products, Pricing, Payments and More
/
210 Best WordPress Twitter Widgets
1 /
1012 Best Contact Form PHP Scripts for 2020
/
-220 Popular WordPress User Interface Elements
/
-410 Best WordPress Star Rating Plugins
/
-412 Best CSS Animations on CodeCanyon
/
-212 Best WordPress Booking and Reservation Plugins
/
120 Best WordPress Calendar Plugins and Widgets
/
-412 Elegant CSS Pricing Tables for Your Latest Web Project
/
824 Best WordPress Form Plugins for 2020
/
-2Getting Started With Django: Newly Updated Course
/
-1Create a Blog for Each Category or Department in Your WooCommerce Store
/
48 Best WordPress Booking and Reservation Plugins
/
-15Best Exit Popups for WordPress Compared
/
18Best Exit Popups for WordPress Compared
/
-311 Best Tab & Accordion WordPress Widgets & Plugins
/
-1012 Best Tab & Accordion WordPress Widgets & Plugins
1 /
1New Course: Practical React Fundamentals
/
2Short Course: Better Angular App Architecture With Modules
/
3Preview Our New Course on Angular Material
/
3Build Your Own CAPTCHA and Contact Form in PHP
/
-3Object-Oriented PHP With Classes and Objects
/
1Best Practices for ARIA Implementation
/
-5Accessible Apps: Barriers to Access and Getting Started With Accessibility
/
-4Dramatically Speed Up Your React Front-End App Using Lazy Loading
/
1715 Best Modern JavaScript Admin Templates for React, Angular, and Vue.js
/
-1615 Best Modern JavaScript Admin Templates for React, Angular and Vue.js
/
319 Best JavaScript Admin Templates for React, Angular, and Vue.js
/
3New Course: Build an App With JavaScript and the MEAN Stack
/
10Hands-on With ARIA: Accessibility Recipes for Web Apps
/
610 Best WordPress Facebook Widgets
13Hands-on With ARIA: Accessibility for eCommerce
/
6New eBooks Available for Subscribers
/
-8Hands-on With ARIA: Homepage Elements and Standard Navigation
/
11
-5Site Accessibility: Getting Started With ARIA
/
5How Secure Are Your JavaScript Open-Source Dependencies?
/
-3New Course: Secure Your WordPress Site With SSL
/
-2Testing Components in React Using Jest and Enzyme
/
-8Testing Components in React Using Jest: The Basics
/
-515 Best PHP Event Calendar and Booking Scripts
/
-3Create Interactive Gradient Animations Using Granim.js
/
11How to Build Complex, Large-Scale Vue.js Apps With Vuex
1 /
-1Examples of Dependency Injection in PHP With Symfony Components
/
-5Set Up Routing in PHP Applications Using the Symfony Routing Component
1 /
9A Beginner’s Guide to Regular Expressions in JavaScript
/
9Introduction to Popmotion: Custom Animation Scrubber
/
-6Introduction to Popmotion: Pointers and Physics
/
-10New Course: Connect to a Database With Laravel’s Eloquent ORM
/
-6How to Create a Custom Settings Panel in WooCommerce
/
-15Building the DOM faster: speculative parsing, async, defer and preload
1 /
520 Useful PHP Scripts Available on CodeCanyon
3 /
51Introduction to the Stimulus Framework
/
-12Single-Page React Applications With the React-Router and React-Transition-Group Modules
712 Best Contact Form PHP Scripts
1 /
-3Getting Started With the Mojs Animation Library: The ShapeSwirl and Stagger Modules
Getting Started With the Mojs Animation Library: The Shape Module
/
-1Getting Started With the Mojs Animation Library: The HTML Module
/
4Project Management Considerations for Your WordPress Project
/
-88 Things That Make Jest the Best React Testing Framework
/
6Creating an Image Editor Using CamanJS: Layers, Blend Modes, and Events
/
1New Short Course: Code a Front-End App With GraphQL and React
/
1Creating an Image Editor Using CamanJS: Applying Basic Filters
/
-12Creating an Image Editor Using CamanJS: Creating Custom Filters and Blend Modes
/
-1Modern Web Scraping With BeautifulSoup and Selenium
/
1Challenge: Create a To-Do List in React
1 /
-2Deploy PHP Web Applications Using Laravel Forge
/
-3Getting Started With the Mojs Animation Library: The Burst Module
/
4
-910 Things Men Can Do to Support Women in Tech
/
-2A Gentle Introduction to Higher-Order Components in React: Best Practices
/
-5A Gentle Introduction to HOC in React: Learn by Example
/
3A Gentle Introduction to Higher-Order Components in React
/
-6Creating Pretty Popup Messages Using SweetAlert2
/
7Creating Stylish and Responsive Progress Bars Using ProgressBar.js
/
1618 Best Contact Form PHP Scripts for 2022
/
-2How to Make a Real-Time Sports Application Using Node.js
/
-2Creating a Blogging App Using Angular & MongoDB: Delete Post
/
-17Set Up an OAuth2 Server Using Passport in Laravel
/
1Creating a Blogging App Using Angular & MongoDB: Edit Post
/
1Introduction to Mocking in Python
/
1Creating a Blogging App Using Angular & MongoDB: Show Post
/
10Creating a Blogging App Using Angular & MongoDB: Home
/
6
3Creating a Blogging App Using Angular & MongoDB: Login
/
12Creating Your First Angular App: Implement Routing
/
12Persisted WordPress Admin Notices: Part 4
/
-2Creating Your First Angular App: Components, Part 2
/
3Persisted WordPress Admin Notices: Part 3
/
4How Laravel Broadcasting Works
/
-1
7Persisted WordPress Admin Notices: Part 2
/
-2Create Your First Angular App: Storing and Accessing Data
/
6Persisted WordPress Admin Notices: Part 1
/
-1Error and Performance Monitoring for Web & Mobile Apps Using Raygun
/
6Using Luxon for Date and Time in JavaScript
7 /
-3How to Create an Audio Oscillator With the Web Audio API
/
-7How to Cache Using Redis in Django Applications
/
220 Essential WordPress Utilities to Manage Your Site
/
-6Introduction to API Calls With React and Axios
/
13Beginner’s Guide to Angular 4: HTTP
/
13Rapid Web Deployment for Laravel With GitHub, Linode, and RunCloud.io
/
7Beginners Guide to Angular 4: Routing
/
-10Beginner’s Guide to Angular 4: Services
/
1Beginner’s Guide to Angular 4: Components
/
1Creating a Drop-Down Menu for Mobile Pages
/
9Introduction to Forms in Angular 4: Writing Custom Form Validators
/
6Getting Started With Redux: Connecting Redux With React
/
14Getting Started With Redux: Learn by Example
/
14Getting Started With Redux: Why Redux?
/
11How to Auto Update WordPress Salts
/
-4How to Download Files in Python
/
-2
-19Eloquent Mutators and Accessors in Laravel
1 /
15
-11
1310 Best HTML5 Sliders for Images and Text
/
8Site Authentication in Node.js: User Signup
/
-2Creating a Task Manager App Using Ionic: Part 2
/
2Creating a Task Manager App Using Ionic: Part 1
/
1Introduction to Forms in Angular 4: Reactive Forms
/
2
4Introduction to Forms in Angular 4: Template-Driven Forms
/
424 Essential WordPress Utilities to Manage Your Site
/
-125 Essential WordPress Utilities to Manage Your Site
/
-10Get Rid of Bugs Quickly Using BugReplay
1 /
-16Manipulating HTML5 Canvas Using Konva: Part 1, Getting Started
/
610 Must-See Easy Digital Downloads Extensions for Your WordPress Site
/
-222 Best WordPress Booking and Reservation Plugins
/
-5Understanding ExpressJS Routing
/
-615 Best WordPress Star Rating Plugins
/
12Creating Your First Angular App: Basics
/
-1Inheritance and Extending Objects With JavaScript
/
-10Introduction to the CSS Grid Layout With Examples
1 /
3
5Performant Animations Using KUTE.js: Part 5, Easing Functions and Attributes
/
-6Performant Animations Using KUTE.js: Part 4, Animating Text
/
-10Performant Animations Using KUTE.js: Part 3, Animating SVG
/
-8New Course: Code a Quiz App With Vue.js
/
-2Performant Animations Using KUTE.js: Part 2, Animating CSS Properties
8Performant Animations Using KUTE.js: Part 1, Getting Started
/
110 Best Responsive HTML5 Sliders for Images and Text (Plus 3 Free Options)
/
-3Single-Page Applications With ngRoute and ngAnimate in AngularJS
/
-14Deferring Tasks in Laravel Using Queues
/
-3
2Site Authentication in Node.js: User Signup and Login
/
10Working With Tables in React, Part Two
/
-17Working With Tables in React, Part One
/
1How to Set Up a Scalable, E-Commerce-Ready WordPress Site Using ClusterCS
/
-2New Course on WordPress Conditional Tags
/
2
-11Building With Vue.js 2 and Firebase
6 /
11
-8
1Best Unique Bootstrap JavaScript Plugins
/
-6
-1Essential JavaScript Libraries and Frameworks You Should Know About
/
6
3Vue.js Crash Course: Create a Simple Blog Using Vue.js
/
-14Build a React App With a Laravel RESTful Back End: Part 1, Laravel 5.5 API
/
2API Authentication With Node.js
/
-4Beginner’s Guide to Angular: HTTP
/
8Beginner’s Guide to Angular: Routing
/
-4Beginners Guide to Angular: Routing
/
-4Beginner’s Guide to Angular: Services
/
2Beginner’s Guide to Angular: Components
/
1How to Create a Custom Authentication Guard in Laravel
/
5Learn Computer Science With JavaScript: Part 3, Loops
/
-3Build Web Applications Using Node.js
/
1Learn Computer Science With JavaScript: Part 4, Functions
/
5Learn Computer Science With JavaScript: Part 2, Conditionals
/
13Create Interactive Charts Using Plotly.js, Part 5: Pie and Gauge Charts
/
-8Create Interactive Charts Using Plotly.js, Part 4: Bubble and Dot Charts
/
16Create Interactive Charts Using Plotly.js, Part 3: Bar Charts
/
-10Awesome JavaScript Libraries and Frameworks You Should Know About
/
-6Create Interactive Charts Using Plotly.js, Part 2: Line Charts
/
-8Bulk Import a CSV File Into MongoDB Using Mongoose With Node.js
/
-5Build a To-Do API With Node, Express, and MongoDB
/
-8Getting Started With End-to-End Testing in Angular Using Protractor
/
11TypeScript for Beginners, Part 4: Classes
/
-15Object-Oriented Programming With JavaScript
/
410 Best Affiliate WooCommerce Plugins Compared
/
6Stateful vs. Stateless Functional Components in React
/
8Make Your JavaScript Code Robust With Flow
/
-2Build a To-Do API With Node and Restify
/
7Testing Components in Angular Using Jasmine: Part 2, Services
/
3Testing Components in Angular Using Jasmine: Part 1
/
-1Creating a Blogging App Using React, Part 6: Tags
/
-10React Crash Course for Beginners, Part 3
/
4React Crash Course for Beginners, Part 2
/
5React Crash Course for Beginners, Part 1
/
3Set Up a React Environment, Part 4
1 /
9Set Up a React Environment, Part 3
/
-9New Course: Get Started With Phoenix
/
-7Set Up a React Environment, Part 2
/
2Command Line Basics and Useful Tricks With the Terminal
/
8How to Create a Real-Time Feed Using Phoenix and React
/
-2Build a React App With a Laravel Back End: Part 2, React
/
2Build a React App With a Laravel RESTful Back End: Part 1, Laravel 9 API
/
-4Creating a Blogging App Using React, Part 5: Profile Page
/
-2Pagination in CodeIgniter: The Complete Guide
/
24JavaScript-Based Animations Using Anime.js, Part 4: Callbacks, Easings, and SVG
JavaScript-Based Animations Using Anime.js, Part 3: Values, Timeline, and Playback
Learn to Code With JavaScript: Part 1, The Basics
/
410 Elegant CSS Pricing Tables for Your Latest Web Project
/
-9Getting Started With the Flux Architecture in React
/
-2Getting Started With Matter.js: The Composites and Composite Modules
/
1Getting Started With Matter.js: The Engine and World Modules
/
1410 More Popular HTML5 Projects for You to Use and Study
/
-21Understand the Basics of Laravel Middleware
/
-1Iterating Fast With Django & Heroku
/
9Creating a Blogging App Using React, Part 4: Update & Delete Posts
/
5Creating a jQuery Plugin for Long Shadow Design
/
-12How to Register & Use Laravel Service Providers
2 /
-13Unit Testing in React: Shallow vs. Static Testing
/
4Creating a Blogging App Using React, Part 3: Add & Display Post
/
14Creating a Blogging App Using React, Part 2: User Sign-Up
20 /
-4Creating a Blogging App Using React, Part 1: User Sign-In
/
69 More Popular HTML5 Projects for You to Use and Study
/
15Creating a Grocery List Manager Using Angular, Part 2: Managing Items
/
99 Elegant CSS Pricing Tables for Your Latest Web Project
/
-3Dynamic Page Templates in WordPress, Part 3
/
-4Angular vs. React: 7 Key Features Compared
/
6Creating a Grocery List Manager Using Angular, Part 1: Add & Display Items
/
2New eBooks Available for Subscribers in June 2017
/
7Create Interactive Charts Using Plotly.js, Part 1: Getting Started
/
10The 5 Best IDEs for WordPress Development (And Why)
/
-233 Popular WordPress User Interface Elements
/
2New Course: How to Hack Your Own App
/
-11How to Install Yii on Windows or a Mac
/
3What Is a JavaScript Operator?
/
-7How to Register and Use Laravel Service Providers
/
9
waly Good blog post. I absolutely love this…