1'use strict'; 2 3import { Asset } from 'expo-asset'; 4import { BarCodeScanner } from 'expo-barcode-scanner'; 5import React from 'react'; 6import { Platform } from 'react-native'; 7 8import * as TestUtils from '../TestUtils'; 9import { mountAndWaitFor as originalMountAndWaitFor } from './helpers'; 10 11export const name = 'BarCodeScanner'; 12const style = { width: 200, height: 200 }; 13 14export async function test(t, { setPortalChild, cleanupPortal }) { 15 const shouldSkipTestsRequiringPermissions = 16 await TestUtils.shouldSkipTestsRequiringPermissionsAsync(); 17 const describeWithPermissions = shouldSkipTestsRequiringPermissions ? t.xdescribe : t.describe; 18 19 const testPoint = (value, expected, inaccuracy) => { 20 t.expect(value).toBeGreaterThanOrEqual(expected - inaccuracy); 21 t.expect(value).toBeLessThan(expected + inaccuracy); 22 }; 23 24 const testBarCodeBounds = (bounds, expectedBounds, sizeInaccuracy, originInaccuracy) => { 25 t.expect(bounds).toBeDefined(); 26 t.expect(typeof bounds.origin).toBe('object'); 27 t.expect(typeof bounds.origin.x).toBe('number'); 28 t.expect(typeof bounds.origin.y).toBe('number'); 29 t.expect(typeof bounds.size).toBe('object'); 30 t.expect(typeof bounds.size.width).toBe('number'); 31 t.expect(typeof bounds.size.height).toBe('number'); 32 33 testPoint(bounds.origin.x, expectedBounds.origin.x, originInaccuracy); 34 testPoint(bounds.origin.y, expectedBounds.origin.y, originInaccuracy); 35 36 testPoint(bounds.size.width, expectedBounds.size.width, sizeInaccuracy); 37 testPoint(bounds.size.height, expectedBounds.size.height, sizeInaccuracy); 38 }; 39 40 describeWithPermissions('BarCodeScanner', () => { 41 const mountAndWaitFor = (child, propName = 'ref') => 42 new Promise((resolve) => { 43 const response = originalMountAndWaitFor(child, propName, setPortalChild); 44 setTimeout(() => resolve(response), 1500); 45 }); 46 47 t.beforeAll(async () => { 48 await TestUtils.acceptPermissionsAndRunCommandAsync(() => { 49 return BarCodeScanner.requestPermissionsAsync(); 50 }); 51 }); 52 53 t.beforeEach(async () => { 54 const { status } = await BarCodeScanner.getPermissionsAsync(); 55 t.expect(status).toEqual('granted'); 56 }); 57 58 t.afterEach(async () => { 59 await cleanupPortal(); 60 }); 61 62 t.describe('when created', () => { 63 t.it('displays the view', async () => { 64 await mountAndWaitFor(<BarCodeScanner style={style} />); 65 }); 66 }); 67 68 t.describe('scanFromURLAsync', () => { 69 t.it('returns empty result when there is no barcode', async () => { 70 const asset = await Asset.fromModule(require('../assets/black-128x256.png')); 71 const result = await BarCodeScanner.scanFromURLAsync(asset.uri); 72 73 t.expect(result).toBeDefined(); 74 t.expect(result.length).toEqual(0); 75 }); 76 77 t.it('scans a QR code from asset', async () => { 78 const asset = await Asset.fromModule(require('../assets/qrcode_expo.jpg')); 79 const result = await BarCodeScanner.scanFromURLAsync(asset.uri); 80 81 t.expect(result).toBeDefined(); 82 t.expect(result.length).toEqual(1); 83 t.expect(result[0]).toBeDefined(); 84 t.expect(result[0].type).toEqual(BarCodeScanner.Constants.BarCodeType.qr); 85 t.expect(result[0].data).toEqual('https://expo.io/'); 86 testBarCodeBounds( 87 result[0].bounds, 88 { 89 origin: { 90 x: 40, 91 y: 40, 92 }, 93 size: { 94 width: 210, 95 height: 210, 96 }, 97 }, 98 2, 99 2 100 ); 101 t.expect(result[0].cornerPoints).toBeDefined(); 102 t.expect(result[0].cornerPoints.length).toEqual(4); 103 }); 104 105 t.it('scans a QR code from photo asset', async () => { 106 // Public domain photo from https://commons.wikimedia.org/wiki/File:QR_Code_Damaged.jpg 107 const asset = await Asset.fromModule(require('../assets/qrcode_photo_wikipedia.jpg')); 108 const result = await BarCodeScanner.scanFromURLAsync(asset.uri); 109 110 t.expect(result).toBeDefined(); 111 t.expect(result.length).toEqual(1); 112 t.expect(result[0]).toBeDefined(); 113 t.expect(result[0].type).toEqual(BarCodeScanner.Constants.BarCodeType.qr); 114 t.expect(result[0].data).toEqual('http://en.m.wikipedia.org'); 115 testBarCodeBounds( 116 result[0].bounds, 117 { 118 origin: { 119 x: 94, 120 y: 94, 121 }, 122 size: { 123 width: 294, 124 height: 296, 125 }, 126 }, 127 10, 128 10 129 ); 130 t.expect(result[0].cornerPoints).toBeDefined(); 131 t.expect(result[0].cornerPoints.length).toEqual(4); 132 }); 133 134 t.it('scans a QR code from base64 URL', async () => { 135 const url = 136 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAQMAAAAk8RryAAAABlBMVEX/' + 137 '//8AAABVwtN+AAAAcElEQVQY04XFMQrAMAgFUCGr4FUCXQO9uuAq/KsEugq2m2bqWx79kQRn1EzGyu' + 138 '1whx/Pc+gxKSnXku4ZNdFQolq2m3jN9/SrD0Ws9l4Ysx5uj9QftqstqQatmey2ftjW6GPI7PvD2iYE' + 139 'uJbEmlT/eAEXiXvHFX7hfQAAAABJRU5ErkJggg=='; 140 const result = await BarCodeScanner.scanFromURLAsync(url); 141 142 t.expect(result).toBeDefined(); 143 t.expect(result.length).toEqual(1); 144 t.expect(result[0]).toBeDefined(); 145 t.expect(result[0].type).toEqual(BarCodeScanner.Constants.BarCodeType.qr); 146 t.expect(result[0].data).toEqual('test'); 147 }); 148 149 if (Platform.OS === 'android') { 150 t.it('scans a Data Matrix code from asset', async () => { 151 const asset = await Asset.fromModule(require('../assets/datamatrix_expo.png')); 152 const result = await BarCodeScanner.scanFromURLAsync(asset.uri); 153 154 t.expect(result).toBeDefined(); 155 t.expect(result.length).toEqual(1); 156 t.expect(result[0]).toBeDefined(); 157 t.expect(result[0].type).toEqual(BarCodeScanner.Constants.BarCodeType.datamatrix); 158 t.expect(result[0].data).toEqual('https://expo.io/'); 159 testBarCodeBounds( 160 result[0].bounds, 161 { 162 origin: { 163 x: 7, 164 y: 7, 165 }, 166 size: { 167 width: 141, 168 height: 141, 169 }, 170 }, 171 2, 172 2 173 ); 174 t.expect(result[0].cornerPoints).toBeDefined(); 175 t.expect(result[0].cornerPoints.length).toEqual(4); 176 }); 177 } 178 179 t.it('respects barCodeTypes parameter', async () => { 180 const asset = await Asset.fromModule(require('../assets/datamatrix_expo.png')); 181 const result = await BarCodeScanner.scanFromURLAsync(asset.uri, [ 182 BarCodeScanner.Constants.BarCodeType.qr, 183 ]); 184 185 t.expect(result).toBeDefined(); 186 t.expect(result.length).toEqual(0); 187 }); 188 189 t.it('works with multiple codes', async () => { 190 const asset = await Asset.fromModule(require('../assets/multiple_codes.png')); 191 const result = await BarCodeScanner.scanFromURLAsync(asset.uri); 192 193 t.expect(result).toBeDefined(); 194 t.expect(result.length > 0).toBe(true); 195 }); 196 }); 197 }); 198} 199