100 Best tips about Java Testing tools
February 7, 2021Thoughts on Selenium 101 Certification from LambdaTest
February 22, 2021The problem
Having some QR Codes to scan from your mobile and or web app is becoming common nowadays. You can read to add a new contact to your phone, distribute it, or even validate a financial transaction.
An approach to get the QR Code image is necessary to guarantee end-to-end (e2e) testing through an application where you need to read it.
There are two different approaches: one for the Mobile app and another one for the Web App.
Library support
We will use ZXing (zebra crossing) an open-source, multi-format 1D/2D barcode image processing library implemented in Java, with ports to other languages. One supported 2D format is the QR Code.
This is the dependency we will use in the project:
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.4.1</version>
</dependency>
Mobile app solution
An easy solution to read the QR Code content in a mobile app is to take a screenshot from the device screen and crop it. We can send the image to Zxing to decode it.
How to read the QR Code content in the mobile app
First, as described above, we must take a screenshot of where the QR Code is. Then we need to crop the image to have only the QR Code in it. After that, we need to decode the image with Zxing to get its contents.
First, let us visualize the test.
@Test
void readQRCode() {
MobileElement qrCodeElement = driver.findElement(By.id("com.example.qrcode:id/imageView"));
File screenshot = driver.getScreenshotAs(OutputType.FILE);
String content = decodeQRCode(generateImage(qrCodeElement, screenshot));
assertThat(content).isEqualTo("f3ce8d4d-074f-483f-9fd0-45c7947fd40c");
}
- On line 3, we found the element which contains the QR Code image and assigns it to the
qrCodeElement
. - On line 4, we took a screenshot and assigned its contents as a
File
. - On line 6, we are using the
decodeQRCode
method sending, as parameters, the element, and the image (screenshot). - On line 7, we are asserting the content returned from the
decodeQRcode
method.
Did you notice that the decodeQRCode
use another method generateImage
? This method uses the element dimensions to crop the QR Code from the screenshot. It’s a better approach to avoid any problem when we are reading it using Zxing.
private BufferedImage generateImage(MobileElement element, File screenshot) {
BufferedImage qrCodeImage = null;
try {
BufferedImage fullImage = ImageIO.read(screenshot);
Point imageLocation = element.getLocation();
int qrCodeImageWidth = element.getSize().getWidth();
int qrCodeImageHeight = element.getSize().getHeight();
int pointXPosition = imageLocation.getX();
int pointYPosition = imageLocation.getY();
qrCodeImage = fullImage.getSubimage(pointXPosition, pointYPosition, qrCodeImageWidth, qrCodeImageHeight);
ImageIO.write(qrCodeImage, "png", screenshot);
} catch (IOException e) {
log.error("Problem during the image generation", e);
}
return qrCodeImage;
}
Now we can use the generateImage
result, which is a BufferedImage
, as a parameter on decodeQRCode
. We are using here the specific Zxing classes to decode the image and return its content.
private static String decodeQRCode(BufferedImage qrCodeImage) {
Result result = null;
try {
LuminanceSource source = new BufferedImageLuminanceSource(qrCodeImage);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
result = new MultiFormatReader().decode(bitmap);
} catch (NotFoundException e) {
log.error("QRCode not found", e);
}
return result.getText();
}
Now, we can use the UUID returned from the QR Code content to assert it. In real life, it could be a key to validate a transaction.
Where to find the code example?
You can take a look at https://github.com/eliasnogueira/appium-read-qrcode to see a complete example of using Appium to interact with the mobile app.
Web App solution
In this Web App solution, we will try to mimic a real-life situation where we need to validate a transaction reading a QR Code content. Usually, it will contain a unique and temporary key to validate the transaction you are doing.
Unlike the Mobile app, we can read the QR Content getting the image from the image src
attribute. After that, we can use Zxing to decode it.
How to read the QR Code content in the web app
We first need to navigate to the page and get the content of the image src attribute.
@Test
void readQRCodeFromURL() {
String qrCodeFile = driver.findElement(By.id("qr")).getAttribute("src");
// get the qr code content and assert the result
String qrCodeResult = decodeQRCode(qrCodeFile);
assertThat(qrCodeResult).isEqualTo("c72a0de5-eba3-4bf0-bde2-fc709e71df29");
}
- On line 3 we are finding the element that is the image and getting the content of the image which is the full image path (in this scenario).
- On line 6, we are using the
decodeQRcode
method to decode it
But Zxing needs an image to read its content. So we need to transform the full image path into an image.
private static String decodeQRCode(Object qrCodeImage) {
Result result = null;
try {
BufferedImage bufferedImage;
// if not (probably it is a URL
if (((String) qrCodeImage).contains("http")) {
bufferedImage = ImageIO.read((new URL((String)qrCodeImage)));
// if is a Base64 String
} else {
byte[] decoded = Base64.decodeBase64((String)qrCodeImage);
bufferedImage = ImageIO.read(new ByteArrayInputStream(decoded));
}
LuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
result = new MultiFormatReader().decode(bitmap);
} catch (NotFoundException | IOException e) {
log.error("Error reading the QR Code", e);
}
return result.getText();
}
- On line 8, we check if the
qrCodeImage
content contains the texthttp
, so we know it is an image path. - On line 9, we are creating a BufferedImage based on the image path (URL)
- Lines 17 to 20 do the trick reading the image content and decoding it using the Zxing classes.
Back to the test, we are getting the QR code content and asserting it by the expected UUID.
Bonus: How to read the QR Code content from a Base64 string
We could have the scenario where, instead of adding the image path in the src attribute, we have an image as a Base64 string. It can happen when it’s generated dynamically.
In the code above, you can see:
- On line 12 an
else
statement - Line 13 gets the content (a Base64 string) and decodes it into a byte array.
- On line 14, we are converting the byte array into a
BufferedImage
. Now we can decode it using Zxing
Where to find the full code example?
You can take a look at https://github.com/eliasnogueira/selenium-read-qrcode/ to see a complete example using Selenium WebDriver interacting with the web app and getting the image content.
Happy tests!
2 Comments
Hi Elias,
How to automate the QR code in mobile app using appium with webdriverio?
Thanks,
Sulaiman
Hi Sulaiman,
Unfortunately, I don’t know how to do this using WebDriverIO. 🙁