Automating APEX using Node.js and Puppeteer

Published by Chris Jansen on

Did you know that Chrome now ships with the feature Headless Chrome it is a tool for automated testing. For example, you may want to run some tests against a real web page, create a PDF of a page, or just inspect how the browser renders an URL, you can use these techniques to test your Oracle APEX applications.

What is Headless Chrome

Headless Chrome allows you to run the browser from the command line without actually opening a Chrome window, it is also possible to watch your script running in the browser.

Puppeteer

Headless Chrome has a rather low-level API, it’s preferred to access it via a library. For this example I am using Puppeteer. Puppeteer is maintained by the Chrome DevTools team.

Installation

To use Puppeteer you need to have Node.js installed. You can find out how to do it here. Puppeteer requires at least Node v6.4.0, but the examples below use async/await which is only supported in Node v7.6.0 or greater.

You can check by using the following command in your terminal:

node --version
or
node –v

Create yourself a directory where you want Puppeteer installed. Open a terminal inside the directory you just created and Install Puppeteer using the following command in your terminal.

npm i puppeteer

The installation may take a couple of minutes. Because it will automatically download a version of Chromium(browser) for you. So you don’t have to setup and maintain a local instance of Chrome manually.

How to run the script

Create yourself a .js file with code of one of the examples. You need to be in the same folder as the file in order to run the code.

node yourfile.js

Taking screenshots with puppeteer

When Puppeteer is taking a screenshot it will simulate a browser window with the desired width. If the page you are testing is responsive, You will see a snapshot of what it looks like at that viewport. You can change its dimensions via the setViewport method.

const puppeteer = require('puppeteer');
 const viewports = [1920, 800, 600, 375];
 (async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://apex.oracle.com/pls/apex/f?p=51138:LOGIN_DESKTOP::::::');
  await page.focus('#P101_USERNAME');
  await page.type('guest', {delay: 100});
  await page.focus('#P101_PASSWORD');
  await page.type('apex_demo' , {delay: 100});
  await page.click('#P101_LOGIN');
  await page.waitForNavigation();
 for(viewport in viewports) {
   let vw = viewports[viewport];
   await page.setViewport({
   width: vw,
   // The height parameter is needed but has no function in our
   // case since we are using fullPage: true @page.screenshot
   height: 0
  });
  await page.screenshot({
   path: `screenshot-W${vw}.png`,
   fullPage: true
  });
 }
 browser.close();
})();

Running this script will generate 4 images inside the folder of the script.

Interacting with Items on the page

With Puppeteer you can access all the elements on the page. Using Puppeteer you can scrape websites, test links, validate forms, etc.
By default headless mode is activated, you have to turn it off in your script. When you run your script it will now open Chromium.

const browser = await puppeteer.launch({
 headless: false,
 });

in this example you log into the application and will add a customer and turn headless mode off so that you can see what’s going on.

const puppeteer = require('puppeteer');
(async () => {
 const browser = await puppeteer.launch({
 headless: false,
 slowMo: 350,
 args: [
 '--start-maximized'
 ]
 });
 const page = await browser.newPage();
  page.setViewport({
  width: 1920,
  height: 1080
 });
 await page.goto('https://apex.oracle.com/pls/apex/f?p=51138:LOGIN_DESKTOP::::::');
 await page.focus('#P101_USERNAME');
 await page.type('guest', {delay: 50});
 await page.focus('#P101_PASSWORD');
 await page.type('apex_demo' , {delay: 50});
 await page.click('#P101_LOGIN');
 await page.waitForNavigation();
 await page.click('#t_TreeNav_1');
 await page.waitForNavigation();
 await page.click('#NEW_CUSTOMER');
 await page.waitForNavigation();
 await page.focus('#P7_CUST_FIRST_NAME');
 await page.type('Test' , {delay: 50});
 await page.focus('#P7_CUST_STREET_ADDRESS1');
 await page.type('123456 Test Drive' , {delay: 50});
 await page.focus('#P7_CUST_CITY');
 await page.type('Atlanta' , {delay: 50});
 await page.focus('#P7_CUST_POSTAL_CODE');
 await page.type('20166' , {delay: 50});
 await page.focus('#P7_CREDIT_LIMIT');
 await page.type('1000' , {delay: 50});
 await page.focus('#P7_CUST_EMAIL');
 await page.type('testusermail.@email.com' , {delay: 50});
 await page.focus('#P7_CUST_LAST_NAME');
 await page.type('User' , {delay: 50});
 await page.click('#P7_CUST_STATE')
 await page.type('D' , {delay: 50});
 await page.press('Enter');
 await page.click('#B34382662543207696578');
})();

Chris Jansen

My passion is creating clean, elegant and creative (web)applications. I’ve worked on everything from Photoshop and Web development to Android, Windows and Web applications. I have a special interest in Javascript frameworks. Aslo don't miss out on my Chrome Extension.