|
| 1 | +// Copyright 2025 The Chromium Authors. All rights reserved. |
| 2 | +// Use of this source code is governed by a BSD-style license that can be |
| 3 | +// found in the LICENSE file. |
| 4 | + |
| 5 | +import * as Platform from '../../core/platform/platform.js'; |
| 6 | +import {assertScreenshot, renderElementIntoDOM} from '../../testing/DOMHelpers.js'; |
| 7 | +import {createFakeRegExpSetting, describeWithEnvironment} from '../../testing/EnvironmentHelpers.js'; |
| 8 | +import {createViewFunctionStub} from '../../testing/ViewFunctionHelpers.js'; |
| 9 | + |
| 10 | +import * as Persistence from './persistence.js'; |
| 11 | + |
| 12 | +const {DEFAULT_VIEW, WorkspaceSettingsTab} = Persistence.WorkspaceSettingsTab; |
| 13 | +const {urlString} = Platform.DevToolsPath; |
| 14 | + |
| 15 | +describeWithEnvironment('WorkspaceSettingsTab view', () => { |
| 16 | + it('renders the exclude regex setting and one card per mapped file system', async () => { |
| 17 | + const target = document.createElement('div'); |
| 18 | + renderElementIntoDOM(target); |
| 19 | + |
| 20 | + const fileSystem = sinon.createStubInstance(Persistence.IsolatedFileSystem.IsolatedFileSystem); |
| 21 | + fileSystem.path.returns(urlString`file:///home/user/foo`); |
| 22 | + fileSystem.excludedFolders.returns(new Set()); |
| 23 | + |
| 24 | + DEFAULT_VIEW( |
| 25 | + { |
| 26 | + excludePatternSetting: createFakeRegExpSetting('fake-exclude-pattern', 'node_modules|.git'), |
| 27 | + fileSystems: [{displayName: 'foo', fileSystem}], |
| 28 | + onAddClicked: () => {}, |
| 29 | + onRemoveClicked: () => {}, |
| 30 | + }, |
| 31 | + {}, target); |
| 32 | + |
| 33 | + await assertScreenshot('persistence/workspace_settings_tab.png'); |
| 34 | + }); |
| 35 | +}); |
| 36 | + |
| 37 | +describeWithEnvironment('WorkspaceSettingsTab widget', () => { |
| 38 | + function createStubFileSystem(path: string) { |
| 39 | + const fileSystem = sinon.createStubInstance(Persistence.IsolatedFileSystem.IsolatedFileSystem); |
| 40 | + fileSystem.path.returns(urlString(path)); |
| 41 | + return fileSystem; |
| 42 | + } |
| 43 | + |
| 44 | + async function setup(initialFileSystemPaths: string[] = []) { |
| 45 | + const fileSystemManager = |
| 46 | + Persistence.IsolatedFileSystemManager.IsolatedFileSystemManager.instance({forceNew: true}); |
| 47 | + const fileSystems = initialFileSystemPaths.map(createStubFileSystem); |
| 48 | + sinon.stub(fileSystemManager, 'fileSystems').returns(fileSystems); |
| 49 | + const addFileSystemStub = sinon.stub(fileSystemManager, 'addFileSystem'); |
| 50 | + const removeFileSystemStub = sinon.stub(fileSystemManager, 'removeFileSystem'); |
| 51 | + const networkPersistenceManager = |
| 52 | + sinon.createStubInstance(Persistence.NetworkPersistenceManager.NetworkPersistenceManager); |
| 53 | + sinon.stub(Persistence.NetworkPersistenceManager.NetworkPersistenceManager, 'instance') |
| 54 | + .returns(networkPersistenceManager); |
| 55 | + |
| 56 | + const view = createViewFunctionStub(WorkspaceSettingsTab); |
| 57 | + const widget = new WorkspaceSettingsTab(view); |
| 58 | + |
| 59 | + const container = document.createElement('div'); |
| 60 | + renderElementIntoDOM(container); |
| 61 | + widget.markAsRoot(); |
| 62 | + widget.show(container); |
| 63 | + await view.nextInput; |
| 64 | + |
| 65 | + return {view, fileSystemManager, fileSystems, addFileSystemStub, removeFileSystemStub, networkPersistenceManager}; |
| 66 | + } |
| 67 | + |
| 68 | + it('uses the exclude folder regex pattern', async () => { |
| 69 | + const {view, fileSystemManager} = await setup(); |
| 70 | + |
| 71 | + assert.strictEqual(view.input.excludePatternSetting, fileSystemManager.workspaceFolderExcludePatternSetting()); |
| 72 | + }); |
| 73 | + |
| 74 | + it('shows the directory name as the card heading', async () => { |
| 75 | + const {view} = await setup(['file:///home/user/foo']); |
| 76 | + |
| 77 | + assert.lengthOf(view.input.fileSystems, 1); |
| 78 | + assert.strictEqual(view.input.fileSystems[0].displayName, 'foo'); |
| 79 | + }); |
| 80 | + |
| 81 | + it('sorts file systems alphabetically', async () => { |
| 82 | + const {view} = await setup(['file:///home/user/zoo', 'file:///home/user/foo']); |
| 83 | + |
| 84 | + assert.lengthOf(view.input.fileSystems, 2); |
| 85 | + assert.strictEqual(view.input.fileSystems[0].fileSystem.path(), 'file:///home/user/foo'); |
| 86 | + assert.strictEqual(view.input.fileSystems[1].fileSystem.path(), 'file:///home/user/zoo'); |
| 87 | + }); |
| 88 | + |
| 89 | + it('listens to FileSystemAdded events', async () => { |
| 90 | + const {view, fileSystems, fileSystemManager} = await setup(); |
| 91 | + const fileSystem = createStubFileSystem('file:///home/user/dev/foo'); |
| 92 | + fileSystems.push(fileSystem); |
| 93 | + |
| 94 | + fileSystemManager.dispatchEventToListeners( |
| 95 | + Persistence.IsolatedFileSystemManager.Events.FileSystemAdded, fileSystem); |
| 96 | + await view.nextInput; |
| 97 | + |
| 98 | + assert.lengthOf(view.input.fileSystems, 1); |
| 99 | + assert.strictEqual(view.input.fileSystems[0].fileSystem, fileSystem); |
| 100 | + }); |
| 101 | + |
| 102 | + it('listens to FileSystemRemoved events', async () => { |
| 103 | + const {view, fileSystems, fileSystemManager} = await setup(['file:///home/user/foo']); |
| 104 | + |
| 105 | + const fileSystem = fileSystems[0]; |
| 106 | + fileSystems.splice(0, 1); |
| 107 | + fileSystemManager.dispatchEventToListeners( |
| 108 | + Persistence.IsolatedFileSystemManager.Events.FileSystemRemoved, fileSystem); |
| 109 | + await view.nextInput; |
| 110 | + |
| 111 | + assert.lengthOf(view.input.fileSystems, 0); |
| 112 | + }); |
| 113 | + |
| 114 | + it('filters out the network persistence file system project', async () => { |
| 115 | + const {view, fileSystems, fileSystemManager, networkPersistenceManager} = await setup(); |
| 116 | + const fileSystem = createStubFileSystem('file:///special-network-fs'); |
| 117 | + fileSystems.push(fileSystem); |
| 118 | + const project = sinon.createStubInstance(Persistence.FileSystemWorkspaceBinding.FileSystem); |
| 119 | + project.fileSystemPath.returns(urlString`file:///special-network-fs`); |
| 120 | + networkPersistenceManager.project.returns(project); |
| 121 | + sinon.stub(fileSystemManager, 'fileSystem').returns(fileSystem); |
| 122 | + |
| 123 | + fileSystemManager.dispatchEventToListeners( |
| 124 | + Persistence.IsolatedFileSystemManager.Events.FileSystemAdded, fileSystem); |
| 125 | + await view.nextInput; |
| 126 | + |
| 127 | + assert.lengthOf(view.input.fileSystems, 0); |
| 128 | + }); |
| 129 | + |
| 130 | + it('wires up addFileSystem', async () => { |
| 131 | + const {view, addFileSystemStub} = await setup(); |
| 132 | + |
| 133 | + view.input.onAddClicked(); |
| 134 | + |
| 135 | + sinon.assert.calledOnce(addFileSystemStub); |
| 136 | + }); |
| 137 | + |
| 138 | + it('wires up removeFileSystem', async () => { |
| 139 | + const {view, fileSystemManager, removeFileSystemStub} = await setup(['file:///home/user/foo']); |
| 140 | + const fileSystem = fileSystemManager.fileSystems()[0]; |
| 141 | + |
| 142 | + view.input.onRemoveClicked(fileSystem as Persistence.IsolatedFileSystem.IsolatedFileSystem); |
| 143 | + |
| 144 | + sinon.assert.calledOnceWithExactly(removeFileSystemStub, fileSystem); |
| 145 | + }); |
| 146 | +}); |
0 commit comments