Learning Jest and Enzyme

JestReactEnzyme

  We know that React is a JavaScript library created by Facebook for building UI components. React makes it painless to create interactive UIs. Design simple views for each state in your application.

   Today’s web applications are more complicated than ever. Libraries like React have opened up a whole new world of application complexity and functionality. In this article, I would like to share two popular JavaScript testing tools, Jest and Enzyme. Both Jest and Enzyme provide powerful tools for testing React UIs. Each is a unit testing tool that empowers you to ensure that the user interface of your web application looks and behaves as expected. Both are actively developed and easily installed using Node Package Manager.

     Jest and Enzyme are specifically designed to test React applications, Jest can be used with any other Javascript app but Enzyme only works with React. Jest can be used without Enzyme to render components and test with snapshots, Enzyme simply adds additional functionality. Enzyme can be used without Jest, however, Enzyme must be paired with another test runner if Jest is not used. Jest as the test runner, assertion library, and mocking library but Enzyme to provide additional testing utilities to interact with UI elements. So together Jest and Enzyme is a powerful testing tool for React applications.

More about Jest

      Jest is a JavaScript unit testing framework, used by Facebook to test services and React applications. As I mentioned Jest is a framework which has a task runner, assertion library, and good mocking support that means it could execute different unit test cases, write its result in console or log files, also could create mocks or verify all the assertions, in short, we can say it will execute the test. CRA (Create React App) comes bundled with Jest; it does not need to be installed separately. Another capability of Jest is that it also provides Snapshot testing, the ability to create a rendered ‘snapshot’ of a component, and compare it to a previously saved ‘snapshot’. The test will fail if the two do not match.

More about Enzyme

    Enzyme, created by Airbnb, adds some great additional utility methods for rendering a component (or multiple components), finding elements, and interacting with elements. As I mentioned Enzyme is a JavaScript Testing utility for React that makes it easier to assert, manipulate, and traverse your React Components output.  It must be installed in addition to tools already bundled with CRA. Enzyme on other hand is a library that wraps packages like React TestUtils, JSDOM and CheerIO to create a simpler interface for writing unit tests. Thus enzyme is not a test runner it doesn’t have its own assertion library as such it just provides a collection of API for unit testing. That’s why it could be integrated with Jest or any other task runner.

Setup Jest and Enzyme

     CRA (Create React App) comes bundled with Jest; it does not need to be installed separately. If you are not using CRA then use below command to install Jest,

npm install –save-dev jest

    You can simply install Enzyme via npm. You will need to install enzyme along with an Adapter corresponding to the version of React (or other UI Component library) you are using. For instance, if you are using enzyme with React 16, you can run below command,

npm install –save-dev enzyme enzyme-adapter-react-16 enzyme-to-json

The next step is to update your package.json file as below,

“jest”:
{
  “snapshotSerializers“: [“enzyme-to-json/serializer”]
}

  enzyme-to-json provides a better component format for snapshot comparison than Enzyme’s internal component representation. snapshotSerializers allows you to minimize code duplication when working with snapshots. Without the serializer each time a component is created in a test it must have the enzyme-to-json method .toJson() used individually before it can be passed to Jest’s snapshot matcher, with the serializer you never use it individually.

expect(toJson(rawRenderedComponent)).toMatchSnapshot();

   With this additional line in package.json it allows you to pass a component created by Enzyme to the Jest .toMatchSnapshot() without calling this interim JSON method.

Create a setupTests.js file at ./src/setupTests.js:

import { configure } from ‘enzyme’;
import Adapter from ‘enzyme-adapter-react-16’;
configure({ adapter: new Adapter() });

    CRA will automatically pick up this file, if not using CRA then also add this line in the same location as snapshotSerializers above:

“setupFiles”: [“./src/setupTests.js”],

Creating a test file

Jest will look for tests in any of the following places:

  • Files with .js suffix in __tests__ folders.
  • Files with .test.js suffix.
  • Files with .spec.js suffix.

    It is a convention to put each test file next to the code it is testing. This makes semantic sense, and also means relative paths are shorter ( ./MyComponent vs ../../MyComponent etc). Below is an example with a filename of MyComponent.test.js,

import React from ‘react’;
import { shallow } from ‘enzyme’;
import MyComponent from ‘./MyComponent’;
describe(‘MyComponent’, () => {
it(‘should render correctly in “debug” mode’, () => { const component = shallow(<MyComponent debug />);
expect(component).toMatchSnapshot();
});
});

   When npm test in CRA ran it will run all test files and output the results to the terminal. Customization flags exist to run against specific files only, or conversely ignore specific files using –– –testPathPattern filename/ and –– –testPathIgnorePatterns filename/.

Discussion about Mount, Shallow, Render

  Mount, Shallow, and Render are different types of methods to render your React components from your application.

import { mount, shallow, render } from ‘enzyme’;

     In order to have a component to test one of the above must be used, as in the example further above.

Mount

  • Full DOM rendering including child components.
  • Ideal for use cases where you have components that may interact with DOM API, or use React lifecycle methods in order to fully test the component.
  • As it actually mounts the component in the DOM .unmount() should be called after each test to stop tests affecting each other.
  • Allows access to both props directly passed into the root component (including default props) and props passed into child components.

Shallow

  • Renders only the single component, not including its children. This is useful to isolate the component for pure unit testing. It protects against changes or bugs in a child component altering the behavior or output of the component under test.
  • As of Enzyme 3 shallow components do have access to lifecycle methods by default.
  • Cannot access props passed into the root component (therefore also not default props), but can those passed into child components, and can test the effect of props passed into the root component. This is as with shallow(<MyComponent />), you’re testing what MyComponent renders – not the element you passed into shallow.

Render

  • Renders to static HTML, including children.
  • It does not have access to React lifecycle methods.
  • Less costly than mount but provides less functionality.

Below is an example of simple non-interactive components:

it(‘should render correctly with no props’, () => {
const component = shallow(<MyComponent/>);
expect(component).toMatchSnapshot();
});

it(‘should render banner text correctly with given strings’, () => {
const strings = [‘one’, ‘two’];
const component = shallow(<MyComponent list={strings} />);
expect(component).toMatchSnapshot();
});

     The Enzyme API has several ways to simulate events or user interactions. If you are wanting to test interacting with a child component then the mount method can be used. Below is an example:

it(‘should be possible to activate button with Spacebar’, () => {
const component = mount(<MyComponent />);
component.find(‘button#my-button-one’).simulate(‘keydown’, { keyCode: 32 });
expect(component).toMatchSnapshot();
component.unmount();
});

NOTE: components are like JavaScript functions. They accept arbitrary inputs (called props) and return React elements describing what should appear on the screen.

Mock Functions

    You may simply want to check that a function passed as props is successfully called. Below is an example to check the props successfully called,

const clickFn = jest.fn();
describe(‘MyComponent’, () => {
it(‘button click should hide component’, () => {
const component = shallow(<MyComponent onClick={clickFn} />);
component.find(‘button#my-button-two’).simulate(‘click’); expect(clickFn).toHaveBeenCalled();
});
});

   Getting more complex, you may wish to mock a function imported and used within MyComponent.js, set its return value, check it is called, and compare its snapshot.

     Lets imagine that within MyComponent.js we import { SaveToStorage } from ‘save-to-storage’ before creating a new SaveToStorage object, which has both TryGetValue and TrySetValue methods. TryGetValue has a default return value of false, if it returns true the component will change. Our component uses these within different button clicks. You can use jest.mock to mock this, as well as jest.fn to provide overrides for the functions within it.

const mockTryGetValue = jest.fn(() => false);
const mockTrySetValue = jest.fn();
jest.mock(‘save-to-storage’, () => ({
SaveToStorage: jest.fn().mockImplementation(() => ({
tryGetValue: mockTryGetValue,
trySetValue: mockTrySetValue,
})),
}));

describe(‘MyComponent’, () => {
it(‘should set storage on save button click’, () => {
mockTryGetValue.mockReturnValueOnce(true);
const component = mount(<MyComponent />);
component.find(‘button#my-button-three’).simulate(‘click’);
expect(mockTryGetValue).toHaveBeenCalled();
expect(component).toMatchSnapshot();
component.unmount();
});
});

Which one is the best among Shallow or Mount?

  • Recommended using shallow as much as possible because unit tests should be isolated as much as possible.
  • No needs to check the units (components) inside a unit (component)when running a single test.
  • When you use mount you are automatically exposed to the logic of all the units (components) in your render tree making it impossible to only test the component.
  • It is more costly in execution time when using the mount, because it requires JSDOM.

     I hope this article will give you a basic knowledge of JavaScript testing utility Jest and Enzyme. Try to utilize Jest and Enzyme together whenever you have an opportunity to test React components.

make it perfect!

 

 

Find Element By Image Locator Strategy in Appium

location-share-top

      Picking the right locator strategy during mobile automation helps to stabilize the automation flow. One of my previous articles, I have already mentioned the selection of the right locator strategy. There I have mentioned about -image selector.

    The -image locator strategy is pretty nifty. Supported on all platforms and drivers, you can pass an image file to Appium and it will try to locate the matching elements on the screen. This supports fuzzy matching and certainly has its applications, but you should only use it when the other locator strategies aren’t working. It may not always behave deterministically, which means it can be a source of test flakiness. Also, unless you have a special code editor, they may be a little more difficult to work with and maintain. Of course, visual UI changes will always break -image selectors, whereas the other selectors only break when the element hierarchy changes. In this article, I would like to explain about find elements By Image. 

     The Appium team finally decided to bite the bullet and support a small set of visual detection features, which are available as of Appium 1.9.0 version and above. An image element looks to your client code exactly like any other element, except that you’ve found it via a new -image locator strategy. Instead of a typical selector (like “foo”), the strings used with this new locator strategy are Base64-encoded image files. The image file used for a particular find action represents a template image that will be used by Appium to match against regions of the screen in order to find the most likely occurrence of the element you’re looking for.

     Suppose you have a scenario like, click on a particular image from your gallery and validate it.  None of the images have any identifying information in the UI tree, and their order changes every time we load the view, so we can’t hardcode an element index if we want to tap a particular image. Find-by-image to the rescue. Actually using this strategy is the same as finding an element using any other strategy:

WebElement element = driver.findElementByImage(base64EncodedImageFile); element.click()

     Of course, for this to work we have to have a Base64-encoded version of your image file. In Java 8 this is pretty straightforward:

// consider that you have a File called myImageFile.You can fetch image path //refImgUrl using ClassLoader class
File myImageFile = Paths.get(refImgUrl.toURI()).toFile();
Base64.getEncoder().encodeToString(Files.readAllBytes(myImageFile.toPath()));

     One another great thing is that finding elements by image supports both implicit and explicit wait strategies, so your tests can robustly wait until your reference image matches something on the screen:

By image = MobileBy.image(base64EncodedImageFile);
new WebDriverWait(driver, 10)
.until(ExpectedConditions.presenceOfElementLocated(image)).click();

     By using the above simple code snippet you can easily navigate to the gallery, click on your particular image, and validate it. Try to use the above find element by image locator strategy in your Appium automation script and enjoy automation.

Reference: Appium Pro

make it perfect!

Real-time Automation Results in Slack Channel

Atlassian_Landing_Page_Marquee

     We know that Slack is a powerful communication tool that brings the team together, wherever you are. Slack offers channels to stay organized and focused on central spaces for conversations, files, tools, and people. Slack provides workspaces, applications, and various team collaboration options. Slack applications help to act as chatbots on various occasions.

     The major advantages of Slack include all team communication in one place, integration with various services, one to one and private groups, the ability to integrate various bots or apps to your slack channel depending on your needs.

    Nowadays, we know that most of the CI tools have the capability to integrate with slack to share real-time test execution results. In this article, I would like to share a couple of utilities written in Java that describe how to send realtime automation test results via slack channels. The automation results included both plain text results and the attached reports.

Prerequisites

  • You must have a slack account.
  • Add the latest jslack dependency into pom.xml if you are using Maven.
  • Add the latest version of following dependencies to pom.xml to handle the API operations,
    • httpclient
    • httpmime  
  • Add extentreports dependency to pom.xml file to generate the HTML automation report.

Step-by-step procedure

  1. Create an account in Slack and then create a Slack workspace. Use https://slack.com/get-started#/
  2. Create a Slack application to communicate with your channel about the automation execution status. Use https://api.slack.com/apps
  3. Create a Slack channel by clicking plus icon right to Channels in your slack workspace. Keep the Slack channel name in your mind and it useful during the scripting.
  4. Add created Slack application to your Slack channel by clicking Add an app link from the slack channel.
  5. Go to https://api.slack.com/apps and select your Slack application. Select Incoming Webhooks and activate it. Scroll down the page and you will get Webhook URL for your channel. This Webhook URL is an important parameter in your script which helps to send the messages to your Slack channel.
  6. Go to OAuth & Permissions section, there you will get Bot User OAuth Access Token which helps the Slack application to send files into your Slack Channel. Copy the Bot User OAuth Access Token and you can use it in the script.
  7. Scroll down in OAuth & Permissions page to reach the Scopes section. Make sure that following scopes are added,
    • Bot Token Scopes:
      • file:write
      • incoming:webhook
    • User Token Scopes:
      • file:write

  I have created two Slack utilities to send real-time test results and the test execution reports to the Slack channel. Following are the methods:

  • sendTestExecutionStatusToSlack helps to send the test results to the Slack channel with the help of the Webhook URL and channel name.
  • sendTestExecutionReportToSlack helps to send the automation test execution report with the help of file upload API, Bot User OAuth Token, and channel name. Following are the detailed implementation of both methods,

private static String urlSlackWebHook = “YOUR_WEBHOOK_URL”;
private static String channelName = “YOUR_CHANNEL_NAME”;
private static String botUserOAuthAccessToken = “YOUR_BOT_USER_OAuth_TOKEN”;

public void sendTestExecutionStatusToSlack(String message) throws Exception {
try {
StringBuilder messageBuider = new StringBuilder();
messageBuider.append(message);
Payload payload = Payload.builder().channel(channelName).text(messageBuider.toString()).build();

WebhookResponse webhookResponse = Slack.getInstance().send(urlSlackWebHook, payload);
webhookResponse.getMessage();
} catch (IOException e) {
System.out.println(“Unexpected Error! WebHook:” + urlSlackWebHook);
}
}

public void sendTestExecutionReportToSlack(String testReportPath) throws Exception {
String url = “https://slack.com/api/files.upload?token=&#8221; + botUserOAuthAccessToken + “&channels=” + channelName
+ “”;
try {
HttpClient httpclient = HttpClientBuilder.create().build();
HttpPost httppost = new HttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
FileBody fileBody = new FileBody(new File(testReportPath));
builder.addPart(“file”, fileBody);
httppost.setEntity(builder.build());
HttpResponse response = null;
response = httpclient.execute(httppost);
HttpEntity result = response.getEntity();
System.out.println(result.toString());
} catch (Exception e) {
e.printStackTrace();
}
}

     You can use above both methods based on your convenience in the automation listener class. If you are using the TestNG framework then you can implement the ITestListener interface and use both methods inside the implemented methods of ITestListener to send real-time test execution results to your Slack channel.

Sample Output: Slack View

Slack Automation Flow

    Try to use the above methods to send real-time test results to Slack channel and enjoy your automation.

make it perfect!

Break the Chain and Start a Session

Zoom meeting

     We know that the entire world is suffering COVID 19 pandemic. Recently, We are hearing the words lockdown, stay home, stay safe, break the chain, work from home. Friends, we know that everyone is working from home in different countries and some are completely isolated. The only way to interact via phone calls, video conferences medium with the help of a bunch of applications. In my case also, I am using the Zoom application for official meetings, virtual birthday celebrations, virtual happy hours activities.

     We know that Zoom is incredibly popular. As I mentioned everyone is using it for their video meetings these days. In this article, I would like to share a start Zoom meeting session to break the chain and enjoy your meetings with the help of Appium. If you already installed Zoom application in Android phone then you just pass package name and activity name via desired capabilities. Otherwise you need to download the Zoom APK and pass the abseolute path of the APK using app capabiltiy. Following desired capabilities will help you to start session with Zoom:

capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, “One Plus”); //use your device name
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, “Android”);
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, “10”);
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.ANDROID_UIAUTOMATOR2);
capabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, “us.zoom.videomeetings”);
capabilities.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, “com.zipow.videobox.LauncherActivity”);
capabilities.setCapability(“udid”, “e6916f40”); //use your device UDID
capabilities.setCapability(MobileCapabilityType.NO_RESET, true);
driver = new AndroidDriver(new URL(“http://0.0.0.0:4723/wd/hub&#8221;), capabilities);

Joining a Zoom Meeting

     The goal is to do something useful with automation, so let’s see how it’s possible to join a Zoom meeting from a device controlled by Appium. Before we begin, we’ll obviously need a Zoom meeting ID. You can assign the Zoom meeting ID to a vaiable let’s say,

private static final String MEETING_ID = “8731672377”; //use your meeting ID to join

     Sometimes, you may need to pass the Zoom meeting password once after you entered the meeting ID. In that case you can assign the Zoom meeting password to a variable and pass that variable in the script. Next step is to identiy the relvant elements from the Zoom application, you can use Appium Desktop to inspect the elements and assigne to variables as below,

By JOIN_MEETING_BUTTON = By.id(“us.zoom.videomeetings:id/btnJoin”);
By MEETING_ID_FIELD = By.id(“us.zoom.videomeetings:id/edtConfNumber”);
By ACTUALLY_JOIN_MEETING_BUTTON = By.id(“us.zoom.videomeetings:id/btnJoin”);
By LEAVE_BTN = By.id(“us.zoom.videomeetings:id/btnLeave”);

Once you identified the elements, you can start your Zoom meeting as follows,

@Test
public void testStartYourZoomMeeting() {
driver.findElement(JOIN_MEETING_BUTTON).click();
driver.findElement(MEETING_ID_FIELD).sendKeys(MEETING_ID);
driver.findElement(ACTUALLY_JOIN_MEETING_BUTTON).click();
Assert.assertTrue(“Failed to Join Zoom Session”, driver.findElement(LEAVE_BTN).isDisplayed());
}

     Dear friends, try to use above logic to start a new Zoom session, join your virtual meetings and break the chain. Stay safe at home.

make it perfect!

 

Record Selenium Automation Flows

BEST-AUTOMATION-TESTING-TOOLS

         We know that automation testing entirely relies on the pre-scripted test which runs automatically to compare actual results with the expected results. This helps the tester to determine whether or not an application performs as expected. Automation testing helps to reduce the effort of the regression test suite execution of manual testers.

         Everyone is familiar with Selenium test automation for Web application and the test automation framework has the capability to generate the reports in different formats like HTML, PDF. Also, the frameworks will generate a screenshot of the UI when a test fails that depends on the configuration in the Automation Listeners. In this article I would like to share the concept of video record your automation flows; even if the test case pass or fail or skip that again depends on your configuration in the Automation Listeners.

Who will help you to record video?

         Selenium has no built-in capability to record the video of the automation flow. Here I am recording the Selenium automation flow with the help of Monte Screen Recorder Java library. The Monte media library used for processing media data. Supported media formats include still images, video, audio, and meta-data. You can record your entire automation flows for future references to share the flow as a demo to your client

Why do we need a video recording?

Video recordings of Selenium test case execution can play a major role. Not only would these help in debugging issues more efficiently, but we can also use recorded videos to show test execution activities to the client or other stakeholders. Additionally, these recorded videos can be added into the project management or defect management tool while creating bugs, which helps in understanding the bug clearly.

How can we achieve the video recording?

Pre-requisites:

  • Create a Maven project.
  • Add following dependencies in pom.xml file:
    • testng
    • selenium-java
    • selenium-server
    • monte-screen-recorder (you will get it from maven repository)
  • Write sample test cases in a test class.
  • Create VideoRecordingUtility class and extends ScreenRecorder class of Monte Recorder library.

       ScreenRecorder class records mouse clicks occurring on other Java Windows running in the same JVM. Mouse clicks occurring in other JVM’s and other processes are not recorded. This ability is useful for performing in JVM recordings of an application that is being tested. This recorder uses four threads. Three capture threads for screen, mouse cursor and audio, and one output thread for the movie writer. ScreenRecorder class is a powerful class with many useful methods, here I am using two important methods of ScreenRecorder class which is start and stop. start method helps to record the screen with a defined type (in this example the type is AVI). stop method helps to stop the screen recording. Here I have created two custom methods startRecording and stopRecording. startRecording method having an argument which included in the name of the video file. You can create an object of ScreenRecorder and call start and stop methods using that object.

Following are the actual logic implementation inside startRecording method:

public static void startRecording(String methodName) throws Exception {
File file = new File(“./AutomationVideoReports/”);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int width = screenSize.width;
int height = screenSize.height;
Rectangle captureSize = new Rectangle(0, 0, width, height);
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
.getDefaultConfiguration();
screenRecorder = new VideoRecordingUtility(gc, captureSize,
new Format(MediaTypeKey, MediaType.FILE, MimeTypeKey, MIME_AVI),
new Format(MediaTypeKey, MediaType.VIDEO, EncodingKey, ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE,
CompressorNameKey, ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE, DepthKey, 24, FrameRateKey,
Rational.valueOf(15), QualityKey, 1.0f, KeyFrameIntervalKey, 15 * 60),
new Format(MediaTypeKey, MediaType.VIDEO, EncodingKey, “black”, FrameRateKey, Rational.valueOf(30)),
null, file, methodName);
screenRecorder.start();
}

Following are the actual logic implementation inside stopRecording method:

public static void stopRecording() throws Exception {
screenRecorder.stop();
}

        The video recording will store in AutomationVideoReports folder. You can use startRecording and stopRecording methods based on your convenience in automation listener class, if you are using TestNG framework then you can implement ITestListener interface and use startRecording and stopRecording inside the implemented methods of ITestListener to record the video of entire test suite flow or record pass/fail/skip cases. Try to use the above logic to record your selenium automation flows and enjoy your automation.

make it perfect!