Mutables for the Tree 🎄 + clean up TreeItem observers and mutables properly (#6032)

* fix: refresh object after conflict error

* fix: recover from error thrown during create

- Ensure that the "Saving" modal dialog is closed

- Notify user of the error, and also print to console to catch in e2e

* fix: default selector tree item to 'mine' folder

- If create fails due to a conflict or otherwise, and the user immediately tries to "Create" again, default the selector tree's selected item to the "mine" folder (which we know exists).

* fix: don't listen to composition if Selector Tree

* refactor: remove dead code

* fix: use MutableDomainObjects in the tree

- Only use mutables and observers if NOT a SelectorTree

- Properly clean up observers and mutables when a parent item is removed from the tree

* test: verify conflicts don't break object creation

* test: verify dialog closes and object is created

* refactor(e2e): update test

- Error notification on 'My Items' folder missing was removed, so don't check for it

* test: increase timeout

* refactor(e2e): use Promise.any()

* refactor(e2e): use Promise instead of polling

* test: add 2p annotation

* test: use `waitForRequest` instead of promise

- tidy up test, add comments describing our pattern

* docs(e2e): add best practices for network tests

* refactor(e2e): avoid using Promise.any

* fix: de-reactify observer and mutable maps

* fix: destroy by path on treeItem close

* fix: don't refresh for synchronized objects

* docs: fix a typo 🔥

* fix: remove existing mutable before adding

* fix: fail fast if these aren't functions

- Remove check for typeof 'function' to not hide any potential coding errors

* fix: walk up navigationPath if item not found

* chore: fix lint errors

* fix: parse conflicted object name correctly

* fix: re-throw conflict error

* fix: Cancel edit mode on conflict
This commit is contained in:
Jesse Mazzella
2022-12-20 13:27:51 -08:00
committed by GitHub
parent 1a4bd0fb55
commit d6e80447ab
9 changed files with 274 additions and 84 deletions

View File

@@ -27,7 +27,7 @@
const { test, expect } = require('../../pluginFixtures');
test.describe("CouchDB Status Indicator @couchdb", () => {
test.describe("CouchDB Status Indicator with mocked responses @couchdb", () => {
test.use({ failOnConsoleError: false });
//TODO BeforeAll Verify CouchDB Connectivity with APIContext
test('Shows green if connected', async ({ page }) => {
@@ -71,38 +71,41 @@ test.describe("CouchDB Status Indicator @couchdb", () => {
});
});
test.describe("CouchDB initialization @couchdb", () => {
test.describe("CouchDB initialization with mocked responses @couchdb", () => {
test.use({ failOnConsoleError: false });
test("'My Items' folder is created if it doesn't exist", async ({ page }) => {
// Store any relevant PUT requests that happen on the page
const createMineFolderRequests = [];
page.on('request', req => {
// eslint-disable-next-line playwright/no-conditional-in-test
if (req.method() === 'PUT' && req.url().endsWith('openmct/mine')) {
createMineFolderRequests.push(req);
}
});
const mockedMissingObjectResponsefromCouchDB = {
status: 404,
contentType: 'application/json',
body: JSON.stringify({})
};
// Override the first request to GET openmct/mine to return a 404
await page.route('**/openmct/mine', route => {
route.fulfill({
status: 404,
contentType: 'application/json',
body: JSON.stringify({})
});
// Override the first request to GET openmct/mine to return a 404.
// This simulates the case of starting Open MCT with a fresh database
// and no "My Items" folder created yet.
await page.route('**/mine', route => {
route.fulfill(mockedMissingObjectResponsefromCouchDB);
}, { times: 1 });
// Go to baseURL
// Set up promise to verify that a PUT request to create "My Items"
// folder was made.
const putMineFolderRequest = page.waitForRequest(req =>
req.url().endsWith('/mine')
&& req.method() === 'PUT');
// Set up promise to verify that a GET request to retrieve "My Items"
// folder was made.
const getMineFolderRequest = page.waitForRequest(req =>
req.url().endsWith('/mine')
&& req.method() === 'GET');
// Go to baseURL.
await page.goto('./', { waitUntil: 'networkidle' });
// Verify that error banner is displayed
const bannerMessage = await page.locator('.c-message-banner__message').innerText();
expect(bannerMessage).toEqual('Failed to retrieve object mine');
// Verify that a PUT request to create "My Items" folder was made
await expect.poll(() => createMineFolderRequests.length, {
message: 'Verify that PUT request to create "mine" folder was made',
timeout: 1000
}).toBeGreaterThanOrEqual(1);
// Wait for both requests to resolve.
await Promise.all([
putMineFolderRequest,
getMineFolderRequest
]);
});
});