From c6ad870a62d03572abc543ac840f6e25a7781c8e Mon Sep 17 00:00:00 2001 From: SJvaca30 <122259127+SJvaca30@users.noreply.github.com> Date: Fri, 12 Jun 2026 16:11:00 +0900 Subject: [PATCH 1/3] [core][ios] Fix DevTools JSON content types with charset (#46336) ## Why Closes #38721. Expo DevTools Network currently treats response bodies as text only when the `Content-Type` header is exactly `application/json`. Valid headers such as `application/json; charset=utf-8` are therefore sent to DevTools as base64 and the Network panel reports that no response data is available. ## How - Normalize response MIME types by stripping `Content-Type` parameters and lowercasing the MIME value before sending CDP response metadata. - Reuse the same normalized content-type check when deciding whether response bodies are text. - Added focused iOS tests for MIME normalization and JSON/text detection with charset parameters. ## Test Plan - `git diff --check` - `xcrun swiftc -parse packages/expo-modules-core/ios/DevTools/CdpNetworkTypes.swift packages/expo-modules-core/ios/DevTools/URLAuthenticationChallengeForwardSender.swift packages/expo-modules-core/ios/DevTools/URLSessionSessionDelegateProxy.swift packages/expo-modules-core/ios/DevTools/URLRequest+httpBodyData.swift packages/expo-modules-core/ios/DevTools/ExpoRequestCdpInterceptor.swift packages/expo-modules-core/ios/DevTools/ExpoRequestInterceptorProtocol.swift packages/expo-modules-core/ios/Tests/ExpoRequestCdpInterceptorTests.swift` # Checklist - [x] Documentation is up to date to reflect these changes. - [x] Conforms with the Documentation Writing Style Guide. Co-authored-by: Tomasz Sapeta --- packages/expo-modules-core/CHANGELOG.md | 1 + .../ios/DevTools/CdpNetworkTypes.swift | 16 +++++++++++++- .../ExpoRequestInterceptorProtocol.swift | 3 +-- .../ExpoRequestCdpInterceptorTests.swift | 22 +++++++++++++++++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/packages/expo-modules-core/CHANGELOG.md b/packages/expo-modules-core/CHANGELOG.md index 27e70e50ef25b0..5a7396f00521f2 100644 --- a/packages/expo-modules-core/CHANGELOG.md +++ b/packages/expo-modules-core/CHANGELOG.md @@ -23,6 +23,7 @@ - [Android] Fix `canAskAgain` returning `false` for re-requestable permissions in the "Ask every time" state. ([#46683](https://github.com/expo/expo/pull/46683) by [@alanjhughes](https://github.com/alanjhughes)) - [Internal] Remove `EventEmitter` re-export global type indirection ([#46719](https://github.com/expo/expo/pull/46719) by [@kitten](https://github.com/kitten)) - [Android] Fixed Expo UI re-compose when switching screens in react-native-screens. ([#46650](https://github.com/expo/expo/pull/46650) by [@kudo](https://github.com/kudo)) +- [iOS] Fix Expo DevTools Network response bodies for JSON content types with parameters. ([#46336](https://github.com/expo/expo/pull/46336) by [@SJvaca30](https://github.com/SJvaca30)) ### 💡 Others diff --git a/packages/expo-modules-core/ios/DevTools/CdpNetworkTypes.swift b/packages/expo-modules-core/ios/DevTools/CdpNetworkTypes.swift index 1890a9c54d2846..46d6d0e242cff7 100644 --- a/packages/expo-modules-core/ios/DevTools/CdpNetworkTypes.swift +++ b/packages/expo-modules-core/ios/DevTools/CdpNetworkTypes.swift @@ -10,6 +10,19 @@ struct CdpNetwork { typealias RequestId = String typealias TimeSinceEpoch = TimeInterval + static func normalizeMimeType(_ contentType: String?) -> String { + return contentType? + .components(separatedBy: ";") + .first? + .trimmingCharacters(in: .whitespacesAndNewlines) + .lowercased() ?? "" + } + + static func isTextContentType(_ contentType: String?) -> Bool { + let mimeType = normalizeMimeType(contentType) + return mimeType.starts(with: "text/") || mimeType == "application/json" + } + enum ResourceType: String, Encodable { case image = "Image" case media = "Media" @@ -19,6 +32,7 @@ struct CdpNetwork { case other = "Other" static func fromMimeType(_ mimeType: String) -> ResourceType { + let mimeType = CdpNetwork.normalizeMimeType(mimeType) if mimeType.starts(with: "image/") { return image } @@ -72,7 +86,7 @@ struct CdpNetwork { } } self.headers = headers - self.mimeType = response.value(forHTTPHeaderField: "Content-Type") ?? "" + self.mimeType = CdpNetwork.normalizeMimeType(response.value(forHTTPHeaderField: "Content-Type")) self.encodedDataLength = encodedDataLength } } diff --git a/packages/expo-modules-core/ios/DevTools/ExpoRequestInterceptorProtocol.swift b/packages/expo-modules-core/ios/DevTools/ExpoRequestInterceptorProtocol.swift index 888cf70e10e3d6..06f9880086944e 100644 --- a/packages/expo-modules-core/ios/DevTools/ExpoRequestInterceptorProtocol.swift +++ b/packages/expo-modules-core/ios/DevTools/ExpoRequestInterceptorProtocol.swift @@ -101,8 +101,7 @@ public final class ExpoRequestInterceptorProtocol: URLProtocol, URLSessionDataDe } else { if let response = task.response as? HTTPURLResponse, let requestId { - let contentType = response.value(forHTTPHeaderField: "Content-Type") - let isText = (contentType?.starts(with: "text/") ?? false) || contentType == "application/json" + let isText = CdpNetwork.isTextContentType(response.value(forHTTPHeaderField: "Content-Type")) Self.delegate.didReceiveResponse( requestId: requestId, task: task, responseBody: responseBody as Data, isText: isText, responseBodyExceedsLimit: responseBodyExceedsLimit) } diff --git a/packages/expo-modules-core/ios/Tests/ExpoRequestCdpInterceptorTests.swift b/packages/expo-modules-core/ios/Tests/ExpoRequestCdpInterceptorTests.swift index 99f92f698e8a8f..d23b0de8efdb67 100644 --- a/packages/expo-modules-core/ios/Tests/ExpoRequestCdpInterceptorTests.swift +++ b/packages/expo-modules-core/ios/Tests/ExpoRequestCdpInterceptorTests.swift @@ -43,6 +43,28 @@ struct ExpoRequestCdpInterceptorTests { return result ?? [:] } + @Test + func `normalizes content type parameters for cdp response`() { + let response = HTTPURLResponse( + url: URL(string: "https://example.com/data")!, + statusCode: 200, + httpVersion: nil, + headerFields: ["Content-Type": "application/json; charset=utf-8"] + )! + let cdpResponse = CdpNetwork.Response(response, encodedDataLength: 2) + + #expect(cdpResponse.mimeType == "application/json") + #expect(CdpNetwork.ResourceType.fromMimeType(" image/png; charset=utf-8 ") == .image) + } + + @Test + func `treats json content type with charset as text`() { + #expect(CdpNetwork.isTextContentType("application/json; charset=utf8")) + #expect(CdpNetwork.isTextContentType("APPLICATION/JSON; charset=utf-8")) + #expect(CdpNetwork.isTextContentType("text/plain; charset=utf-8")) + #expect(!CdpNetwork.isTextContentType("image/png")) + } + @Test func `simple json data`() async throws { mockDelegate.events.removeAll() From 45ae493dc1de421fd4a16f68f85931ce54f160ab Mon Sep 17 00:00:00 2001 From: Self Not Found Date: Fri, 12 Jun 2026 07:38:17 +0000 Subject: [PATCH 2/3] [android][file-system] Apply Dispatchers.IO to File.bytes()/text()/base64()/write() (#46376) # Why Inspired by #44359, This could improve performance when reading/writing multiple files with the async API at the same time for Android # How 1. Apply `suspend`/`withContext(Dispatchers.IO)` to the async wrapper of io related functions in `FileSystemModule.kt` 2. Replace `TypedArray` with `NativeArrayBuffer` for thread safety and `ArrayBuffer` support # Test Plan 1. `pnpm et check expo-file-system` passed 2. Filesystem related tests in `apps/bare-expo` passed on Android # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- packages/expo-file-system/CHANGELOG.md | 2 ++ .../expo/modules/filesystem/FileSystemFile.kt | 6 ++-- .../modules/filesystem/FileSystemModule.kt | 36 ++++++++++++------- .../internal/NativeFileSystem.types.d.ts | 4 +-- .../internal/NativeFileSystem.types.d.ts.map | 2 +- .../expo-file-system/ios/FileSystemFile.swift | 6 ++-- .../ios/FileSystemModule.swift | 8 ++--- packages/expo-file-system/mocks/FileSystem.ts | 4 +-- .../src/__tests__/FileSystem-test.native.ts | 8 +++++ .../src/internal/NativeFileSystem.types.ts | 4 +-- 10 files changed, 51 insertions(+), 29 deletions(-) diff --git a/packages/expo-file-system/CHANGELOG.md b/packages/expo-file-system/CHANGELOG.md index e9b022db6eed4e..57782bf9ad11cd 100644 --- a/packages/expo-file-system/CHANGELOG.md +++ b/packages/expo-file-system/CHANGELOG.md @@ -13,6 +13,8 @@ ### 💡 Others +- Improve read/write performance on Android by applying `withContext(Dispatchers.IO)` when possible. ([#46376](https://github.com/expo/expo/pull/46376) by [@wh201906](https://github.com/wh201906)) + ## 56.0.7 — 2026-05-20 ### 🛠 Breaking changes diff --git a/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemFile.kt b/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemFile.kt index 815f3b5a263080..9403c7ae245d8d 100644 --- a/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemFile.kt +++ b/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemFile.kt @@ -5,8 +5,8 @@ import android.util.Base64 import expo.modules.filesystem.unifiedfile.JavaFile import expo.modules.filesystem.unifiedfile.SAFDocumentFile import expo.modules.kotlin.exception.Exceptions +import expo.modules.kotlin.jni.NativeArrayBuffer import expo.modules.kotlin.services.FilePermissionService -import expo.modules.kotlin.typedarray.TypedArray import java.io.FileOutputStream import java.security.MessageDigest @@ -84,7 +84,7 @@ class FileSystemFile(uri: Uri) : FileSystemPath(uri) { } } - fun write(content: TypedArray, append: Boolean = false) { + fun write(content: NativeArrayBuffer, append: Boolean = false) { validateType() validatePermission(FilePermissionService.Permission.WRITE) if (!exists) { @@ -92,7 +92,7 @@ class FileSystemFile(uri: Uri) : FileSystemPath(uri) { } if (uri.isContentUri) { file.outputStream(append).use { outputStream -> - val array = ByteArray(content.length) + val array = ByteArray(content.size()) content.toDirectBuffer().get(array) outputStream.write(array) } diff --git a/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.kt b/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.kt index b0a55370a00ce1..33cb228c4b9a53 100644 --- a/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.kt +++ b/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.kt @@ -8,12 +8,14 @@ import androidx.annotation.RequiresApi import expo.modules.kotlin.activityresult.AppContextActivityResultLauncher import expo.modules.kotlin.exception.Exceptions import expo.modules.kotlin.functions.Coroutine +import expo.modules.kotlin.jni.NativeArrayBuffer import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition import expo.modules.kotlin.services.FilePermissionService -import expo.modules.kotlin.typedarray.TypedArray import expo.modules.kotlin.types.Either +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext import java.io.File import java.net.URI @@ -31,7 +33,7 @@ class FileSystemModule : Module() { private fun writeToFile( file: FileSystemFile, - content: Either, + content: Either, options: WriteOptions? ) { val append = options?.append ?: false @@ -43,8 +45,8 @@ class FileSystemModule : Module() { file.write(it, append) } } - } else if (content.`is`(TypedArray::class)) { - content.get(TypedArray::class).let { + } else if (content.`is`(NativeArrayBuffer::class)) { + content.get(NativeArrayBuffer::class).let { file.write(it, append) } } @@ -159,32 +161,40 @@ class FileSystemModule : Module() { file.create(options ?: CreateOptions()) } - AsyncFunction("write") Coroutine { file: FileSystemFile, content: Either, options: WriteOptions? -> - writeToFile(file, content, options) + AsyncFunction("write") Coroutine { file: FileSystemFile, content: Either, options: WriteOptions? -> + withContext(Dispatchers.IO) { + writeToFile(file, content, options) + } } - Function("writeSync") { file: FileSystemFile, content: Either, options: WriteOptions? -> + Function("writeSync") { file: FileSystemFile, content: Either, options: WriteOptions? -> writeToFile(file, content, options) } - AsyncFunction("text") { file: FileSystemFile -> - file.text() + AsyncFunction("text") Coroutine { file: FileSystemFile -> + withContext(Dispatchers.IO) { + file.text() + } } Function("textSync") { file: FileSystemFile -> file.text() } - AsyncFunction("base64") { file: FileSystemFile -> - file.base64() + AsyncFunction("base64") Coroutine { file: FileSystemFile -> + withContext(Dispatchers.IO) { + file.base64() + } } Function("base64Sync") { file: FileSystemFile -> file.base64() } - AsyncFunction("bytes") { file: FileSystemFile -> - file.bytes() + AsyncFunction("bytes") Coroutine { file: FileSystemFile -> + withContext(Dispatchers.IO) { + file.bytes() + } } Function("bytesSync") { file: FileSystemFile -> diff --git a/packages/expo-file-system/build/internal/NativeFileSystem.types.d.ts b/packages/expo-file-system/build/internal/NativeFileSystem.types.d.ts index 930b1841721d0c..285342efce2d18 100644 --- a/packages/expo-file-system/build/internal/NativeFileSystem.types.d.ts +++ b/packages/expo-file-system/build/internal/NativeFileSystem.types.d.ts @@ -152,12 +152,12 @@ export declare class NativeFileSystemFile { * Writes content to the file. * @param content The content to write into the file. */ - write(content: string | Uint8Array, options?: FileWriteOptions): Promise; + write(content: string | Uint8Array | ArrayBuffer, options?: FileWriteOptions): Promise; /** * Writes content to the file. * @param content The content to write into the file. */ - writeSync(content: string | Uint8Array, options?: FileWriteOptions): void; + writeSync(content: string | Uint8Array | ArrayBuffer, options?: FileWriteOptions): void; /** * Deletes a file. * diff --git a/packages/expo-file-system/build/internal/NativeFileSystem.types.d.ts.map b/packages/expo-file-system/build/internal/NativeFileSystem.types.d.ts.map index bb23bffd09b80f..9de6a4c7fa78af 100644 --- a/packages/expo-file-system/build/internal/NativeFileSystem.types.d.ts.map +++ b/packages/expo-file-system/build/internal/NativeFileSystem.types.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"NativeFileSystem.types.d.ts","sourceRoot":"","sources":["../../src/internal/NativeFileSystem.types.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"NativeFileSystem.types.d.ts","sourceRoot":"","sources":["../../src/internal/NativeFileSystem.types.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-file-system/ios/FileSystemFile.swift b/packages/expo-file-system/ios/FileSystemFile.swift index bc589eb722288a..d12a12900290e0 100644 --- a/packages/expo-file-system/ios/FileSystemFile.swift +++ b/packages/expo-file-system/ios/FileSystemFile.swift @@ -105,9 +105,11 @@ internal final class FileSystemFile: FileSystemPath { } // TODO: blob support - func write(_ content: TypedArray, append: Bool = false) throws { + func write(_ content: NativeArrayBuffer, append: Bool = false) throws { try withCorrectTypeAndScopedAccess(permission: .write) { - let data = Data(bytes: content.rawPointer, count: content.byteLength) + let data = content.withUnsafeBytes { rawBuffer in + Data(rawBuffer) + } if append { try writeAppending(data) } else { diff --git a/packages/expo-file-system/ios/FileSystemModule.swift b/packages/expo-file-system/ios/FileSystemModule.swift index 96288466cd055e..bba24c53f8d020 100644 --- a/packages/expo-file-system/ios/FileSystemModule.swift +++ b/packages/expo-file-system/ios/FileSystemModule.swift @@ -36,7 +36,7 @@ public final class FileSystemModule: Module { private func writeToFile( _ file: FileSystemFile, - content: Either, + content: Either, options: WriteOptions? ) throws { let append = options?.append ?? false @@ -49,7 +49,7 @@ public final class FileSystemModule: Module { } else { try file.write(content, append: append) } - } else if let content: TypedArray = content.get() { + } else if let content: NativeArrayBuffer = content.get() { try file.write(content, append: append) } } @@ -194,11 +194,11 @@ public final class FileSystemModule: Module { return try file.info(options: options ?? InfoOptions()) } - AsyncFunction("write") { (file: FileSystemFile, content: Either, options: WriteOptions?) in + AsyncFunction("write") { (file: FileSystemFile, content: Either, options: WriteOptions?) in try writeToFile(file, content: content, options: options) } - Function("writeSync") { (file: FileSystemFile, content: Either, options: WriteOptions?) in + Function("writeSync") { (file: FileSystemFile, content: Either, options: WriteOptions?) in try writeToFile(file, content: content, options: options) } diff --git a/packages/expo-file-system/mocks/FileSystem.ts b/packages/expo-file-system/mocks/FileSystem.ts index 8ac9cbee99528f..0bf3181d8d6dfc 100644 --- a/packages/expo-file-system/mocks/FileSystem.ts +++ b/packages/expo-file-system/mocks/FileSystem.ts @@ -247,7 +247,7 @@ export class FileSystemFile { } writeSync( - content: string | Uint8Array, + content: string | Uint8Array | ArrayBuffer, options: { append?: boolean; encoding?: 'utf8' | 'base64' } = {} ): void { assertParent(this.uri, false); @@ -281,7 +281,7 @@ export class FileSystemFile { } async write( - content: string | Uint8Array, + content: string | Uint8Array | ArrayBuffer, options: { append?: boolean; encoding?: 'utf8' | 'base64' } = {} ): Promise { this.writeSync(content, options); diff --git a/packages/expo-file-system/src/__tests__/FileSystem-test.native.ts b/packages/expo-file-system/src/__tests__/FileSystem-test.native.ts index 6253c1a7af64fe..444e8aaf842aeb 100644 --- a/packages/expo-file-system/src/__tests__/FileSystem-test.native.ts +++ b/packages/expo-file-system/src/__tests__/FileSystem-test.native.ts @@ -236,6 +236,14 @@ describe('expo-file-system behavioral mock', () => { await expect(file.bytes()).resolves.toEqual(payload); }); + it('File.writeSync(ArrayBuffer) and File.bytes() roundtrip byte-for-byte', async () => { + const file = new File(Paths.cache, 'bin-buffer.dat'); + const payload = Uint8Array.from([6, 7, 8, 9]).buffer; + file.writeSync(payload); + expect(Array.from(file.bytesSync())).toEqual([6, 7, 8, 9]); + await expect(file.bytes()).resolves.toEqual(new Uint8Array(payload)); + }); + it('File.writeSync with append option appends to existing bytes', () => { const file = new File(Paths.cache, 'log.txt'); file.writeSync('a'); diff --git a/packages/expo-file-system/src/internal/NativeFileSystem.types.ts b/packages/expo-file-system/src/internal/NativeFileSystem.types.ts index 01f8a6ad20aed6..17c8d8d6710ae4 100644 --- a/packages/expo-file-system/src/internal/NativeFileSystem.types.ts +++ b/packages/expo-file-system/src/internal/NativeFileSystem.types.ts @@ -205,13 +205,13 @@ export declare class NativeFileSystemFile { * Writes content to the file. * @param content The content to write into the file. */ - write(content: string | Uint8Array, options?: FileWriteOptions): Promise; + write(content: string | Uint8Array | ArrayBuffer, options?: FileWriteOptions): Promise; /** * Writes content to the file. * @param content The content to write into the file. */ - writeSync(content: string | Uint8Array, options?: FileWriteOptions): void; + writeSync(content: string | Uint8Array | ArrayBuffer, options?: FileWriteOptions): void; /** * Deletes a file. From ea8c92ba01701f6e89036393831d086dd07c200f Mon Sep 17 00:00:00 2001 From: Wiktor Smaga Date: Fri, 12 Jun 2026 11:46:37 +0200 Subject: [PATCH 3/3] [test-suite] Fix TypeScript warnings in MediaLibraryNext (#46489) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Why The recently added stricter TypeScript config started flagging untyped and nullable variables as errors in the test suit. # How Added types and nullable checks. # Test Plan BareExpo ✅ --- apps/test-suite/tests/MediaLibraryNext.ts | 227 ++++++++++++---------- 1 file changed, 126 insertions(+), 101 deletions(-) diff --git a/apps/test-suite/tests/MediaLibraryNext.ts b/apps/test-suite/tests/MediaLibraryNext.ts index 049a96bca5afb0..d94107afde2ded 100644 --- a/apps/test-suite/tests/MediaLibraryNext.ts +++ b/apps/test-suite/tests/MediaLibraryNext.ts @@ -19,33 +19,37 @@ const exifJpgPath = require('../assets/exif_data_image.jpg'); const pngPath = require('../assets/icons/app.png'); const jpgPath = require('../assets/qrcode_expo.jpg'); -export async function test(t) { - let permissions; - let files; - let jpgFile, pngFile, mp4File, mp3File, exifJpgFile; - - const checkIfAllPermissionsWereGranted = () => { - if (Platform.OS === 'ios') { - return permissions.accessPrivileges === 'all'; - } - return permissions.granted; - }; +export async function test(t: any) { + let localUris: string[]; + let mp3FileLocalUri: string; + let pngFileLocalUri: string; + let jpgFileLocalUri: string; + let mp4FileLocalUri: string; + let exifJpgFileLocalUri: string; t.beforeAll(async () => { - [mp3File] = await ExpoAsset.loadAsync(mp3Path); - [pngFile] = await ExpoAsset.loadAsync(pngPath); - [jpgFile] = await ExpoAsset.loadAsync(jpgPath); - [mp4File] = await ExpoAsset.loadAsync(mp4Path); - [exifJpgFile] = await ExpoAsset.loadAsync(exifJpgPath); - files = [pngFile, jpgFile, mp4File]; - permissions = await requestPermissionsAsync(); - if (!checkIfAllPermissionsWereGranted()) { - console.warn('Tests will fail - not enough permissions to run them.'); + const permissionResponse = await requestPermissionsAsync(); + if (!permissionResponse.granted) { + throw new Error('Permission to access media library is required for testing'); } + + const loadAssetLocalUri = async (assetModule: any, assetName: string): Promise => { + const [asset] = await ExpoAsset.loadAsync(assetModule); + if (asset.localUri === null) { + throw new Error(`Failed to load ${assetName} file for testing`); + } + return asset.localUri; + }; + mp3FileLocalUri = await loadAssetLocalUri(mp3Path, 'MP3'); + pngFileLocalUri = await loadAssetLocalUri(pngPath, 'PNG'); + jpgFileLocalUri = await loadAssetLocalUri(jpgPath, 'JPG'); + mp4FileLocalUri = await loadAssetLocalUri(mp4Path, 'MP4'); + exifJpgFileLocalUri = await loadAssetLocalUri(exifJpgPath, 'EXIF JPG'); + localUris = [pngFileLocalUri, jpgFileLocalUri, mp4FileLocalUri]; }); - let albumsContainer = []; - let assetsContainer = []; + let albumsContainer: (Album | Album[])[] = []; + let assetsContainer: (Asset | Asset[])[] = []; t.afterAll(async () => { try { @@ -60,16 +64,17 @@ export async function test(t) { t.describe('Stress tests', () => { t.it('creating files with the same filename', async () => { - for (let i = 0; i < 40; i++) { - const asset = await Asset.create(pngFile.localUri); + const assetCount = 40; + for (let i = 0; i < assetCount; i++) { + const asset = await Asset.create(pngFileLocalUri); assetsContainer.push(asset); } }); t.it('moving files with the same filename to album', async () => { - const createdAssets = []; + const createdAssets: Asset[] = []; for (let i = 0; i < 40; i++) { - const album = await Album.create(createAlbumName(`temp album ${i}`), [pngFile.localUri]); + const album = await Album.create(createAlbumName(`temp album ${i}`), [pngFileLocalUri]); albumsContainer.push(album); createdAssets.push(...(await album.getAssets())); } @@ -82,19 +87,16 @@ export async function test(t) { t.describe('Album creation', () => { t.it('creates an album from a list of paths', async () => { const albumName = createAlbumName('album from paths'); - const album = await Album.create( - albumName, - files.map((f) => f.localUri) - ); + const album = await Album.create(albumName, localUris); albumsContainer.push(album); const assets = await album.getAssets(); - t.expect(assets.length).toBe(files.length); + t.expect(assets.length).toBe(localUris.length); t.expect(await album.getTitle()).toBe(albumName); }); t.it('creates an album from a list of assets', async () => { // given - const assets = await Promise.all(files.map((f) => Asset.create(f.localUri))); + const assets = await Promise.all(localUris.map((uri) => Asset.create(uri))); assetsContainer.push(...assets); const albumName = createAlbumName('album from assets'); @@ -103,7 +105,7 @@ export async function test(t) { albumsContainer.push(album); // then - t.expect(assets.length).toBe(files.length); + t.expect(assets.length).toBe(localUris.length); t.expect(await album.getTitle()).toBe(albumName); const fetchedAssets = await album.getAssets(); if (Platform.OS === 'android' && Platform.Version >= 30) { @@ -118,7 +120,7 @@ export async function test(t) { if (Platform.OS === 'android') { t.it('when creating an album from a list of assets should correctly move files', async () => { // given - const assets = await Promise.all(files.map((f) => Asset.create(f.localUri))); + const assets = await Promise.all(localUris.map((uri) => Asset.create(uri))); assetsContainer.push(...assets); const oldAssetUris = await Promise.all(assets.map((asset) => asset.getUri())); const albumName = createAlbumName('album from assets move'); @@ -135,7 +137,7 @@ export async function test(t) { }); t.it('when creating an album from a list of assets should correctly copy files', async () => { // given - const assets = await Promise.all(files.map((f) => Asset.create(f.localUri))); + const assets = await Promise.all(localUris.map((uri) => Asset.create(uri))); assetsContainer.push(...assets); const oldAssetUris = await Promise.all(assets.map((asset) => asset.getUri())); const albumName = createAlbumName('album from assets copy'); @@ -159,7 +161,7 @@ export async function test(t) { t.describe('Asset creation', () => { t.it('creates a PNG asset', async () => { - const asset = await Asset.create(pngFile.localUri); + const asset = await Asset.create(pngFileLocalUri); assetsContainer.push(asset); t.expect(asset.id).toBeDefined(); }); @@ -167,7 +169,7 @@ export async function test(t) { if (Platform.OS === 'ios') { t.it('fails when creating an MP3 asset', async () => { try { - const asset = await Asset.create(mp3File.localUri); + const asset = await Asset.create(mp3FileLocalUri); assetsContainer.push(asset); t.fail(); } catch (e) { @@ -176,32 +178,32 @@ export async function test(t) { }); } else { t.it('creates an MP3 asset', async () => { - const asset = await Asset.create(mp3File.localUri); + const asset = await Asset.create(mp3FileLocalUri); assetsContainer.push(asset); t.expect(asset.id).toBeDefined(); }); } t.it('creates an MP4 asset', async () => { - const asset = await Asset.create(mp4File.localUri); + const asset = await Asset.create(mp4FileLocalUri); assetsContainer.push(asset); t.expect(asset.id).toBeDefined(); }); t.it('creates a JPG asset', async () => { - const asset = await Asset.create(jpgFile.localUri); + const asset = await Asset.create(jpgFileLocalUri); assetsContainer.push(asset); t.expect(asset.id).toBeDefined(); }); t.it('creates an asset inside an album', async () => { const albumName = createAlbumName('asset inside album'); - const firstAsset = await Asset.create(jpgFile.localUri); + const firstAsset = await Asset.create(jpgFileLocalUri); assetsContainer.push(firstAsset); const album = await Album.create(albumName, [firstAsset]); albumsContainer.push(album); - const newAsset = await Asset.create(jpgFile.localUri, album); + const newAsset = await Asset.create(jpgFileLocalUri, album); assetsContainer.push(newAsset); t.expect(newAsset.id).toBeDefined(); @@ -212,8 +214,8 @@ export async function test(t) { if (Platform.OS === 'android') { t.it('creates two different assets with different uri from the same source', async () => { - const firstAsset = await Asset.create(jpgFile.localUri); - const secondAsset = await Asset.create(jpgFile.localUri); + const firstAsset = await Asset.create(jpgFileLocalUri); + const secondAsset = await Asset.create(jpgFileLocalUri); assetsContainer.push([firstAsset, secondAsset]); const firstUri = await firstAsset.getUri(); const secondUri = await secondAsset.getUri(); @@ -227,10 +229,13 @@ export async function test(t) { t.describe('Album get', () => { t.it('gets an album by title', async () => { const albumName = createAlbumName('gets an album by title'); - const album = await Album.create(albumName, [jpgFile.localUri], true); + const album = await Album.create(albumName, [jpgFileLocalUri], true); albumsContainer.push(album); const fetchedAlbum = await Album.get(albumName); + if (fetchedAlbum === null) { + return t.fail('Album should be found by title'); + } t.expect(fetchedAlbum).toBeDefined(); t.expect(fetchedAlbum.id).toBe(album.id); }); @@ -240,7 +245,7 @@ export async function test(t) { t.it('includes a newly created album', async () => { // given const albumName = createAlbumName('getAll includes new album'); - const album = await Album.create(albumName, [jpgFile.localUri], true); + const album = await Album.create(albumName, [jpgFileLocalUri], true); albumsContainer.push(album); // when @@ -253,7 +258,7 @@ export async function test(t) { t.it('does not include a deleted album', async () => { // given const albumName = createAlbumName('getAll excludes deleted album'); - const album = await Album.create(albumName, [jpgFile.localUri], true); + const album = await Album.create(albumName, [jpgFileLocalUri], true); assetsContainer.push(await album.getAssets()); await album.delete(); @@ -268,7 +273,7 @@ export async function test(t) { t.describe('Album deletion', () => { t.it('deletes an album', async () => { const albumName = createAlbumName('album deletion'); - const album = await Album.create(albumName, [jpgFile.localUri], true); + const album = await Album.create(albumName, [jpgFileLocalUri], true); albumsContainer.push(album); assetsContainer.push(await album.getAssets()); @@ -287,10 +292,10 @@ export async function test(t) { t.describe('Add asset to album', () => { t.it('adds an asset to an existing album', async () => { const albumName = createAlbumName('add asset'); - const album = await Album.create(albumName, [jpgFile.localUri], true); + const album = await Album.create(albumName, [jpgFileLocalUri], true); albumsContainer.push(album); - const newAsset = await Asset.create(pngFile.localUri); + const newAsset = await Asset.create(pngFileLocalUri); const oldUri = await newAsset.getUri(); assetsContainer.push(newAsset); await album.add(newAsset); @@ -307,12 +312,12 @@ export async function test(t) { t.it('adds an array of assets to an existing album', async () => { // given const albumName = createAlbumName('add asset array'); - const album = await Album.create(albumName, [jpgFile.localUri], true); + const album = await Album.create(albumName, [jpgFileLocalUri], true); albumsContainer.push(album); const newAssets = await Promise.all([ - Asset.create(pngFile.localUri), - Asset.create(mp4File.localUri), + Asset.create(pngFileLocalUri), + Asset.create(mp4FileLocalUri), ]); const oldUris = await Promise.all(newAssets.map((asset) => asset.getUri())); assetsContainer.push(...newAssets); @@ -337,7 +342,7 @@ export async function test(t) { t.it('does nothing when adding an empty array to an album', async () => { // given const albumName = createAlbumName('add empty array'); - const album = await Album.create(albumName, [jpgFile.localUri], true); + const album = await Album.create(albumName, [jpgFileLocalUri], true); albumsContainer.push(album); assetsContainer.push(...(await album.getAssets())); @@ -354,7 +359,7 @@ export async function test(t) { t.describe('Remove assets from album', () => { t.it('removes an asset from an album without deleting it from the library', async () => { const albumName = createAlbumName('remove asset'); - const album = await Album.create(albumName, [jpgFile.localUri], true); + const album = await Album.create(albumName, [jpgFileLocalUri], true); albumsContainer.push(album); const assetToRemove = (await album.getAssets())[0]; @@ -371,10 +376,10 @@ export async function test(t) { t.it('removes only specified assets, leaving others in the album', async () => { const albumName = createAlbumName('remove partial'); - const album = await Album.create(albumName, [jpgFile.localUri], true); + const album = await Album.create(albumName, [jpgFileLocalUri], true); albumsContainer.push(album); - const newAsset = await Asset.create(pngFile.localUri); + const newAsset = await Asset.create(pngFileLocalUri); assetsContainer.push(newAsset); await album.add(newAsset); @@ -390,7 +395,7 @@ export async function test(t) { t.it('does nothing when called with an empty array', async () => { const albumName = createAlbumName('does nothing when called with an empty array'); - const album = await Album.create(albumName, [jpgFile.localUri], true); + const album = await Album.create(albumName, [jpgFileLocalUri], true); albumsContainer.push(album); const assetsBefore = await album.getAssets(); @@ -404,10 +409,10 @@ export async function test(t) { t.it('does nothing when asset does not belong to the album', async () => { const albumName = createAlbumName('does nothing when asset does not belong to the album'); - const album = await Album.create(albumName, [jpgFile.localUri], true); + const album = await Album.create(albumName, [jpgFileLocalUri], true); albumsContainer.push(album); - const outsideAsset = await Asset.create(pngFile.localUri); + const outsideAsset = await Asset.create(pngFileLocalUri); assetsContainer.push(outsideAsset); const assetsBefore = await album.getAssets(); @@ -429,7 +434,7 @@ export async function test(t) { let asset: Asset; t.beforeEach(async () => { - asset = await Asset.create(pngFile.localUri); + asset = await Asset.create(pngFileLocalUri); assetsContainer.push(asset); }); @@ -467,6 +472,9 @@ export async function test(t) { t.it('returns correct modification time', async () => { const modificationTime = await asset.getModificationTime(); + if (modificationTime === null) { + return t.fail('Modification time should not be null for an asset'); + } t.expect(new Date(modificationTime).getFullYear()).toBeGreaterThan(1970); t.expect(modificationTime).toBeGreaterThan(0); }); @@ -515,7 +523,7 @@ export async function test(t) { let videoAsset: Asset; t.beforeEach(async () => { - videoAsset = await Asset.create(mp4File.localUri); + videoAsset = await Asset.create(mp4FileLocalUri); assetsContainer.push(videoAsset); }); @@ -546,6 +554,9 @@ export async function test(t) { t.it('returns correct modification time', async () => { const modificationTime = await videoAsset.getModificationTime(); + if (modificationTime === null) { + return t.fail('Modification time should not be null for a video asset'); + } t.expect(new Date(modificationTime).getFullYear()).toBeGreaterThan(1970); t.expect(modificationTime).toBeGreaterThan(0); }); @@ -564,7 +575,7 @@ export async function test(t) { t.describe('Asset query', () => { t.it('limit works correctly', async () => { // given - const createdAssets = await Promise.all(files.map((f) => Asset.create(f.localUri))); + const createdAssets = await Promise.all(localUris.map((uri) => Asset.create(uri))); assetsContainer.push(...createdAssets); // when const assets = await new Query().limit(3).exe(); @@ -575,7 +586,7 @@ export async function test(t) { t.it('offset works correctly', async () => { // given - const createdAssets = await Promise.all(files.map((f) => Asset.create(f.localUri))); + const createdAssets = await Promise.all(localUris.map((uri) => Asset.create(uri))); assetsContainer.push(...createdAssets); // when const query = new Query(); @@ -589,7 +600,7 @@ export async function test(t) { t.it('limit 0 returns no assets', async () => { // given - const createdAssets = await Promise.all(files.map((f) => Asset.create(f.localUri))); + const createdAssets = await Promise.all(localUris.map((uri) => Asset.create(uri))); assetsContainer.push(...createdAssets); const albumName = createAlbumName('limit 0 returns no assets'); const album = await Album.create(albumName, createdAssets); @@ -602,7 +613,7 @@ export async function test(t) { t.it('offset outside of bounds works correctly', async () => { // given - const asset = await Asset.create(pngFile.localUri); + const asset = await Asset.create(pngFileLocalUri); assetsContainer.push(asset); const albumName = createAlbumName('offset outside of bounds works correctly'); const album = await Album.create(albumName, [asset]); @@ -615,7 +626,7 @@ export async function test(t) { t.it('mediatype image works correctly', async () => { // given - const asset = await Asset.create(pngFile.localUri); + const asset = await Asset.create(pngFileLocalUri); assetsContainer.push(asset); // when const [imageAsset] = await new Query() @@ -629,7 +640,7 @@ export async function test(t) { t.it('mediatype video works correctly', async () => { // given - const asset = await Asset.create(mp4File.localUri); + const asset = await Asset.create(mp4FileLocalUri); assetsContainer.push(asset); // when const [videoAsset] = await new Query() @@ -643,8 +654,8 @@ export async function test(t) { t.it('isFavorite filter works correctly', async () => { // given const albumName = createAlbumName('isFavorite filter'); - const favoriteAsset = await Asset.create(pngFile.localUri); - const nonFavoriteAsset = await Asset.create(jpgFile.localUri); + const favoriteAsset = await Asset.create(pngFileLocalUri); + const nonFavoriteAsset = await Asset.create(jpgFileLocalUri); assetsContainer.push(favoriteAsset, nonFavoriteAsset); const album = await Album.create(albumName, [favoriteAsset, nonFavoriteAsset]); albumsContainer.push(album); @@ -673,7 +684,7 @@ export async function test(t) { if (Platform.OS !== 'ios') { t.it('mediatype audio works correctly', async () => { // given - const asset = await Asset.create(mp3File.localUri); + const asset = await Asset.create(mp3FileLocalUri); assetsContainer.push(asset); // when const query = new Query().limit(1).within(AssetField.MEDIA_TYPE, [MediaType.AUDIO]); @@ -686,7 +697,7 @@ export async function test(t) { t.it('album works correctly', async () => { // given const albumName = createAlbumName('album works correctly'); - const asset = await Asset.create(mp4File.localUri); + const asset = await Asset.create(mp4FileLocalUri); assetsContainer.push(asset); const album = await Album.create(albumName, [asset]); albumsContainer.push(album); @@ -701,16 +712,20 @@ export async function test(t) { t.it('modification time and gte/lte work correctly', async () => { // given const albumName = createAlbumName('modification time and gt/lt work correctly'); - const asset = await Asset.create(pngFile.localUri); + const asset = await Asset.create(pngFileLocalUri); assetsContainer.push(asset); const album = await Album.create(albumName, [asset]); albumsContainer.push(album); // when + const modificationTime = await asset.getModificationTime(); + if (modificationTime === null) { + return t.fail('Modification time should not be null for an asset'); + } const [queriedAsset] = await new Query() .limit(1) .album(album) - .gte(AssetField.MODIFICATION_TIME, (await asset.getModificationTime()) - 1000) - .lte(AssetField.MODIFICATION_TIME, (await asset.getModificationTime()) + 1000) + .gte(AssetField.MODIFICATION_TIME, modificationTime - 1000) + .lte(AssetField.MODIFICATION_TIME, modificationTime + 1000) .exe(); // then t.expect(queriedAsset.id).toBe(asset.id); @@ -719,7 +734,7 @@ export async function test(t) { t.it('height and gte work correctly', async () => { // given const albumName = createAlbumName('height and gte work correctly'); - const asset = await Asset.create(pngFile.localUri); + const asset = await Asset.create(pngFileLocalUri); assetsContainer.push(asset); const album = await Album.create(albumName, [asset]); albumsContainer.push(album); @@ -738,16 +753,20 @@ export async function test(t) { const albumName = createAlbumName( 'modification time and incorrect gte/lte returns empty array' ); - const asset = await Asset.create(pngFile.localUri); + const asset = await Asset.create(pngFileLocalUri); assetsContainer.push(asset); const album = await Album.create(albumName, [asset]); albumsContainer.push(album); // when + const modificationTime = await asset.getModificationTime(); + if (modificationTime === null) { + return t.fail('Modification time should not be null for an asset'); + } const [queriedAsset] = await new Query() .limit(1) .album(album) - .gte(AssetField.MODIFICATION_TIME, (await asset.getModificationTime()) + 1000) - .lte(AssetField.MODIFICATION_TIME, (await asset.getModificationTime()) - 1000) + .gte(AssetField.MODIFICATION_TIME, modificationTime + 1000) + .lte(AssetField.MODIFICATION_TIME, modificationTime - 1000) .exe(); // then t.expect(queriedAsset).toBeUndefined(); @@ -756,7 +775,7 @@ export async function test(t) { t.it('creation time works correctly', async () => { // given const albumName = createAlbumName('album works correctly'); - const asset = await Asset.create(mp4File.localUri); + const asset = await Asset.create(mp4FileLocalUri); assetsContainer.push(asset); const album = await Album.create(albumName, [asset]); albumsContainer.push(album); @@ -770,8 +789,8 @@ export async function test(t) { t.it('orderBy height works correctly', async () => { // given - const shorterAsset = await Asset.create(pngFile.localUri); - const tallerAsset = await Asset.create(jpgFile.localUri); + const shorterAsset = await Asset.create(pngFileLocalUri); + const tallerAsset = await Asset.create(jpgFileLocalUri); assetsContainer.push(tallerAsset); assetsContainer.push(shorterAsset); const albumName = createAlbumName('orderBy height works correctly'); @@ -789,8 +808,8 @@ export async function test(t) { t.it('orderBy mediaType works correctly', async () => { // given - const videoAsset = await Asset.create(mp4File.localUri); - const photoAsset = await Asset.create(jpgFile.localUri); + const videoAsset = await Asset.create(mp4FileLocalUri); + const photoAsset = await Asset.create(jpgFileLocalUri); assetsContainer.push(videoAsset); assetsContainer.push(photoAsset); const albumName = createAlbumName('orderBy mediaType works correctly'); @@ -806,9 +825,9 @@ export async function test(t) { t.it('orderBy combined works correctly', async () => { // given - const videoAsset = await Asset.create(mp4File.localUri); - const shorterAsset = await Asset.create(pngFile.localUri); - const tallerAsset = await Asset.create(jpgFile.localUri); + const videoAsset = await Asset.create(mp4FileLocalUri); + const shorterAsset = await Asset.create(pngFileLocalUri); + const tallerAsset = await Asset.create(jpgFileLocalUri); assetsContainer.push(videoAsset); assetsContainer.push(shorterAsset); assetsContainer.push(tallerAsset); @@ -830,9 +849,9 @@ export async function test(t) { t.it('orderBy ascending works correctly', async () => { // given - const videoAsset = await Asset.create(mp4File.localUri); - const shorterAsset = await Asset.create(pngFile.localUri); - const tallerAsset = await Asset.create(jpgFile.localUri); + const videoAsset = await Asset.create(mp4FileLocalUri); + const shorterAsset = await Asset.create(pngFileLocalUri); + const tallerAsset = await Asset.create(jpgFileLocalUri); assetsContainer.push(videoAsset); assetsContainer.push(shorterAsset); assetsContainer.push(tallerAsset); @@ -854,7 +873,7 @@ export async function test(t) { t.it('exeForMetadata works correctly for images', async () => { // given - const asset = await Asset.create(pngFile.localUri); + const asset = await Asset.create(pngFileLocalUri); assetsContainer.push(asset); const albumName = createAlbumName('exeForMetadata works correctly for images'); const album = await Album.create(albumName, [asset]); @@ -864,6 +883,9 @@ export async function test(t) { // then t.expect(results.length).toBe(1); const result = results[0]; + if (result.modificationTime === null) { + return t.fail('Modification time should not be null for an asset'); + } t.expect(result.id).toBeDefined(); t.expect(result.creationTime).toBeDefined(); t.expect(result.duration).toBe(null); @@ -878,7 +900,7 @@ export async function test(t) { t.it('exeForMetadata works correctly for videos', async () => { // given - const asset = await Asset.create(mp4File.localUri); + const asset = await Asset.create(mp4FileLocalUri); assetsContainer.push(asset); const albumName = createAlbumName('exeForMetadata works correctly for videos'); const album = await Album.create(albumName, [asset]); @@ -888,6 +910,9 @@ export async function test(t) { // then t.expect(results.length).toBe(1); const result = results[0]; + if (result.modificationTime === null) { + return t.fail('Modification time should not be null for a video asset'); + } t.expect(result.id).toBeDefined(); t.expect(result.creationTime).toBeDefined(); t.expect(result.duration).toBeGreaterThan(0); @@ -905,7 +930,7 @@ export async function test(t) { if (Platform.OS === 'ios') { t.it('returns all albums the asset belongs to', async () => { // given - const asset = await Asset.create(pngFile.localUri); + const asset = await Asset.create(pngFileLocalUri); assetsContainer.push(asset); const album1 = await Album.create(createAlbumName('getAlbums_ios_1'), [asset], false); const album2 = await Album.create(createAlbumName('getAlbums_ios_2'), [asset], false); @@ -922,7 +947,7 @@ export async function test(t) { if (Platform.OS === 'android') { t.it('returns only the album the asset currently resides in', async () => { // given - const asset = await Asset.create(jpgFile.localUri); + const asset = await Asset.create(jpgFileLocalUri); assetsContainer.push(asset); const album1 = await Album.create( createAlbumName('returns only the album the asset currently resides in 1'), @@ -930,7 +955,7 @@ export async function test(t) { true ); albumsContainer.push(album1); - const otherAsset = await Asset.create(pngFile.localUri); + const otherAsset = await Asset.create(pngFileLocalUri); assetsContainer.push(otherAsset); const album2 = await Album.create( createAlbumName('returns only the album the asset currently resides in 2'), @@ -951,7 +976,7 @@ export async function test(t) { t.describe('Exif interface', () => { t.it('returns location for jpg image', async () => { // given - const asset = await Asset.create(exifJpgFile.localUri); + const asset = await Asset.create(exifJpgFileLocalUri); assetsContainer.push(asset); // when const location = await asset.getLocation(); @@ -965,7 +990,7 @@ export async function test(t) { t.it('returns exif data for jpg image', async () => { // given - const asset = await Asset.create(exifJpgFile.localUri); + const asset = await Asset.create(exifJpgFileLocalUri); assetsContainer.push(asset); // when const exif = await asset.getExif(); @@ -998,7 +1023,7 @@ export async function test(t) { t.it('addListener is called when asset is created', async () => { const spy = t.jasmine.createSpy('addAsset spy', () => {}); const subscription = addListener(spy); - const asset = await Asset.create(pngFile.localUri); + const asset = await Asset.create(pngFileLocalUri); t.expect(asset).not.toBeNull(); await timeoutWrapper(() => t.expect(spy).toHaveBeenCalled(), WAIT_TIME); @@ -1011,7 +1036,7 @@ export async function test(t) { const spy = t.jasmine.createSpy('remove spy', () => {}); const subscription = addListener(spy); subscription.remove(); - const asset = await Asset.create(pngFile.localUri); + const asset = await Asset.create(pngFileLocalUri); t.expect(asset).not.toBeNull(); await timeoutWrapper(() => t.expect(spy).not.toHaveBeenCalled(), WAIT_TIME); @@ -1021,7 +1046,7 @@ export async function test(t) { t.it('addListener is called when asset is deleted', async () => { const spy = t.jasmine.createSpy('deleteAsset spy', () => {}); - const asset = await Asset.create(pngFile.localUri); + const asset = await Asset.create(pngFileLocalUri); const subscription = addListener(spy); t.expect(asset).not.toBeNull(); @@ -1035,7 +1060,7 @@ export async function test(t) { addListener(spy); removeAllListeners(); - const asset = await Asset.create(pngFile.localUri); + const asset = await Asset.create(pngFileLocalUri); t.expect(asset).not.toBeNull(); await timeoutWrapper(() => t.expect(spy).not.toHaveBeenCalled(), WAIT_TIME);