async function updateTestItemFromRawDataInternal()

in src/client/testing/testController/common/testItemUtilities.ts [306:487]


async function updateTestItemFromRawDataInternal(
    item: TestItem,
    testController: TestController,
    idToRawData: Map<string, TestData>,
    testRoot: string,
    rawDataSet: RawDiscoveredTests[],
    token?: CancellationToken,
): Promise<void> {
    if (token?.isCancellationRequested) {
        return;
    }

    const rawId = idToRawData.get(item.id)?.rawId;
    if (!rawId) {
        traceError(`Unknown node id: ${item.id}`);
        return;
    }

    const nodeRawData = rawDataSet.filter(
        (r) =>
            r.root === rawId ||
            r.rootid === rawId ||
            r.parents.find((p) => p.id === rawId) ||
            r.tests.find((t) => t.id === rawId),
    );

    if (nodeRawData.length === 0 && item.parent) {
        removeItemByIdFromChildren(idToRawData, item.parent, [item.id]);
        traceVerbose(`Following test item was removed Reason: No-Raw-Data ${item.id}`);
        return;
    }

    if (nodeRawData.length > 1) {
        // Something is wrong, there can only be one test node with that id
        traceError(`Multiple (${nodeRawData.length}) raw data nodes had the same id: ${rawId}`);
        return;
    }

    if (rawId === nodeRawData[0].root || rawId === nodeRawData[0].rootid) {
        // This is a test root node, we need to update the entire tree
        // The update children and remove any child that does not have raw data.

        await asyncForEach(testItemCollectionToArray(item.children), async (c) => {
            await updateTestItemFromRawData(c, testController, idToRawData, testRoot, nodeRawData, token);
        });

        // Create child nodes that are new.
        // We only need to look at rawData.parents. Since at this level we either have folder or file.
        const rawChildNodes = nodeRawData[0].parents.filter((p) => p.parentid === '.' || p.parentid === rawId);
        const existingNodes: string[] = [];
        item.children.forEach((c) => existingNodes.push(idToRawData.get(c.id)?.rawId ?? ''));

        await asyncForEach(
            rawChildNodes.filter((r) => !existingNodes.includes(r.id)),
            async (r) => {
                const childItem =
                    r.kind === 'file'
                        ? createFolderOrFileTestItem(testController, idToRawData, testRoot, r as RawTestFile)
                        : createFolderOrFileTestItem(testController, idToRawData, testRoot, r as RawTestFolder);
                item.children.add(childItem);
                await updateTestItemFromRawData(childItem, testController, idToRawData, testRoot, nodeRawData, token);
            },
        );

        return;
    }

    // First check if this is a parent node
    const rawData = nodeRawData[0].parents.filter((r) => r.id === rawId);
    if (rawData.length === 1) {
        // This is either a File/Folder/Collection node

        // Update the node data
        switch (rawData[0].kind) {
            case 'file':
                updateFolderOrFileTestItem(item, idToRawData, testRoot, rawData[0] as RawTestFile);
                break;
            case 'folder':
                updateFolderOrFileTestItem(item, idToRawData, testRoot, rawData[0] as RawTestFolder);
                break;
            case 'suite':
                updateCollectionTestItem(item, idToRawData, testRoot, rawData[0] as RawTestSuite);
                break;
            case 'function':
                updateCollectionTestItem(item, idToRawData, testRoot, rawData[0] as RawTestFunction);
                break;
            default:
                break;
        }

        // The update children and remove any child that does not have raw data.
        await asyncForEach(testItemCollectionToArray(item.children), async (c) => {
            await updateTestItemFromRawData(c, testController, idToRawData, testRoot, nodeRawData, token);
        });

        // Create child nodes that are new.
        // Get the existing child node ids so we can skip them
        const existingNodes: string[] = [];
        item.children.forEach((c) => existingNodes.push(idToRawData.get(c.id)?.rawId ?? ''));

        // We first look at rawData.parents. Since at this level we either have folder or file.
        // The current node is potentially a parent of one of these "parent" nodes or it is a parent
        // of test case nodes. We will handle Test case nodes after handling parents.
        const rawChildNodes = nodeRawData[0].parents.filter((p) => p.parentid === rawId);
        await asyncForEach(
            rawChildNodes.filter((r) => !existingNodes.includes(r.id)),
            async (r) => {
                let childItem;
                switch (r.kind) {
                    case 'file':
                        childItem = createFolderOrFileTestItem(testController, idToRawData, testRoot, r as RawTestFile);
                        break;
                    case 'folder':
                        childItem = createFolderOrFileTestItem(
                            testController,
                            idToRawData,
                            testRoot,
                            r as RawTestFolder,
                        );
                        break;
                    case 'suite':
                        childItem = createCollectionTestItem(testController, idToRawData, testRoot, r as RawTestSuite);
                        break;
                    case 'function':
                        childItem = createCollectionTestItem(
                            testController,
                            idToRawData,
                            testRoot,
                            r as RawTestFunction,
                        );
                        break;
                    default:
                        break;
                }
                if (childItem) {
                    item.children.add(childItem);
                    // This node can potentially have children. So treat it like a new node and update it.
                    await updateTestItemFromRawData(
                        childItem,
                        testController,
                        idToRawData,
                        testRoot,
                        nodeRawData,
                        token,
                    );
                }
            },
        );

        // Now we will look at test case nodes. Create any test case node that does not already exist.
        const rawTestCaseNodes = nodeRawData[0].tests.filter((p) => p.parentid === rawId);
        rawTestCaseNodes
            .filter((r) => !existingNodes.includes(r.id))
            .forEach((r) => {
                const childItem = createTestCaseItem(testController, idToRawData, testRoot, r);
                item.children.add(childItem);
            });

        return;
    }

    if (rawData.length > 1) {
        // Something is wrong, there can only be one test node with that id
        traceError(`Multiple (${rawData.length}) raw data nodes had the same id: ${rawId}`);
        return;
    }

    // We are here this means rawData.length === 0
    // The node is probably is test case node. Try and find it.
    const rawCaseData = nodeRawData[0].tests.filter((r) => r.id === rawId);

    if (rawCaseData.length === 1) {
        // This is a test case node
        updateTestCaseItem(item, idToRawData, testRoot, rawCaseData[0]);
        return;
    }

    if (rawCaseData.length > 1) {
        // Something is wrong, there can only be one test node with that id
        traceError(`Multiple (${rawCaseData.length}) raw data nodes had the same id: ${rawId}`);
    }
}