Skip to content
File

Blob: src/workerd/api/tests/webfs-test.js

javascript136 lines
1// Copyright (c) 2025 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4import { ok, strictEqual, deepStrictEqual, rejects } from 'node:assert';
5 
6ok(navigator.storage instanceof StorageManager);
7 
8const dir = await navigator.storage.getDirectory();
9ok(dir instanceof FileSystemDirectoryHandle);
10strictEqual(dir.name, '');
11 
12const bundle = await dir.getDirectoryHandle('bundle');
13const temp = await dir.getDirectoryHandle('tmp');
14 
15strictEqual(bundle.name, 'bundle');
16strictEqual(temp.name, 'tmp');
17 
18let count = 0;
19for await (const node of dir) {
20 // The node is an Array of [name, handle]
21 strictEqual(typeof node[0], 'string');
22 ok(node[1] instanceof FileSystemDirectoryHandle);
23 count++;
24}
25strictEqual(count, 3);
26 
27const names = await Array.fromAsync(dir.keys());
28deepStrictEqual(names, ['bundle', 'tmp', 'dev']);
29 
30export const webfsTest = {
31 async test() {
32 const file = await temp.getFileHandle('foo.txt', { create: true });
33 ok(file instanceof FileSystemFileHandle);
34 const writable = await file.createWritable();
35 ok(writable instanceof FileSystemWritableFileStream);
36 const enc = new TextEncoder();
37 await writable.write(enc.encode('hello world'));
38 
39 // The original file contents remain unchanged until the writable is closed.
40 let f = await file.getFile();
41 strictEqual(await f.text(), '');
42 await writable.close();
43 
44 // Once closed, however, the file contents are updated.
45 f = await file.getFile();
46 strictEqual(await f.text(), 'hello world');
47 
48 const file2 = await temp.getFileHandle('foo.txt');
49 ok(file2 instanceof FileSystemFileHandle);
50 const fileStream = await file2.getFile();
51 ok(fileStream instanceof File);
52 const text = await fileStream.text();
53 strictEqual(text, 'hello world');
54 
55 await rejects(temp.getFileHandle('does-not-exist.txt', { create: false }), {
56 message: 'Not found',
57 });
58 },
59};
60 
61// TODO(node-fs): Rework this test now that createSyncAccessHandle has been removed.
62// We can still test this using the the stream API but it needs to be structured
63// a little differently.
64// export const deviceTest = {
65// async test() {
66// // Test /dev/null
67// const dev = await dir.getDirectoryHandle('dev');
68// const devNull = await dev.getFileHandle('null');
69// ok(devNull instanceof FileSystemFileHandle);
70// const sync = await devNull.createSyncAccessHandle();
71// const enc = new TextEncoder();
72// strictEqual(sync.getSize(), 0);
73// sync.write(enc.encode('hello world'));
74// strictEqual(sync.getSize(), 0);
75// strictEqual(sync.read(new Uint8Array(11)), 0);
76 
77// // Test /dev/zero
78// const devZero = await dev.getFileHandle('zero');
79// ok(devZero instanceof FileSystemFileHandle);
80// const syncZero = await devZero.createSyncAccessHandle();
81// strictEqual(syncZero.getSize(), 0);
82// syncZero.write(enc.encode('hello world'));
83// strictEqual(syncZero.getSize(), 0);
84// const u8 = new Buffer.from([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
85// const zeroes = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
86// strictEqual(syncZero.read(u8), u8.byteLength);
87// deepStrictEqual(u8, zeroes);
88 
89// // Test /dev/full
90// const devFull = await dev.getFileHandle('full');
91// ok(devFull instanceof FileSystemFileHandle);
92// const syncFull = await devFull.createSyncAccessHandle();
93// strictEqual(syncFull.getSize(), 0);
94// throws(() => syncFull.write(enc.encode('hello world')), {
95// message: 'Operation not permitted',
96// name: 'NotAllowedError',
97// });
98// strictEqual(syncFull.getSize(), 0);
99// const u8Full = new Buffer.from([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
100// strictEqual(syncFull.read(u8Full), 11);
101// deepStrictEqual(u8Full, zeroes);
102 
103// // Test /dev/random
104// const devRandom = await dev.getFileHandle('random');
105// ok(devRandom instanceof FileSystemFileHandle);
106// const syncRandom = await devRandom.createSyncAccessHandle();
107// strictEqual(syncRandom.getSize(), 0);
108// throws(() => syncRandom.write(enc.encode('hello world')), {
109// message: 'Operation not permitted',
110// name: 'NotAllowedError',
111// });
112// strictEqual(syncRandom.getSize(), 0);
113// const u8Random = new Buffer.from([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
114// const check = new Buffer.from([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
115// strictEqual(syncRandom.read(u8Random), 11);
116// notDeepStrictEqual(u8Random, check);
117// },
118// };
119 
120export const asyncIteratorTest = {
121 async test() {
122 const dir = await navigator.storage.getDirectory();
123 
124 let count = 0;
125 for await (const node of dir) {
126 // The node is an Array of [name, handle]
127 ok(node[1] instanceof FileSystemDirectoryHandle);
128 count++;
129 }
130 strictEqual(count, 3);
131 
132 const names = await Array.fromAsync(dir.keys());
133 deepStrictEqual(names, ['bundle', 'tmp', 'dev']);
134 },
135};