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