Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .npmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
registry=https://registry.npmjs.org/
registry=https://packagefeedproxy.microsoft.io/npm/
Comment thread
millerds marked this conversation as resolved.
12,051 changes: 6,306 additions & 5,745 deletions package-lock.json

Large diffs are not rendered by default.

43 changes: 14 additions & 29 deletions test/end-to-end/src/host-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ export const testExcelEnd2End = async (testServerPort: number): Promise<void> =>
await testHelpers.closeWorkbook();
Promise.resolve();
});
} catch (error) {
testHelpers.addTestResult(testValues, "output-message", getErrorMessage(error), "");
await sendTestResults(testValues, testServerPort);
testValues.pop();
Promise.reject();
} catch (err) {
testValues = [];
testHelpers.addErrorResult(testValues, `runTest failed: ${testHelpers.formatError(err)}`);
await sendTestResults(testValues, testServerPort).catch(() => {});
}
};

Expand All @@ -45,7 +44,7 @@ export const testPowerPointEnd2End = async (testServerPort: number): Promise<voi
await testHelpers.sleep(2000);

// Get output of executed taskpane code
PowerPoint.run(async (context: PowerPoint.RequestContext) => {
await PowerPoint.run(async (context: PowerPoint.RequestContext) => {
// get text from inserted text shape
const slide = context.presentation.getSelectedSlides().getItemAt(0);
// eslint-disable-next-line office-addins/load-object-before-read, office-addins/call-sync-before-read
Expand All @@ -61,11 +60,10 @@ export const testPowerPointEnd2End = async (testServerPort: number): Promise<voi
testValues.pop();
Promise.resolve();
});
} catch (error) {
testHelpers.addTestResult(testValues, "output-message", getErrorMessage(error), "");
await sendTestResults(testValues, testServerPort);
testValues.pop();
Promise.reject();
} catch (err) {
testValues = [];
testHelpers.addErrorResult(testValues, `runTest failed: ${testHelpers.formatError(err)}`);
await sendTestResults(testValues, testServerPort).catch(() => {});
}
};

Expand All @@ -76,7 +74,7 @@ export const testWordEnd2End = async (testServerPort: number): Promise<void> =>
await testHelpers.sleep(2000);

// Get output of executed taskpane code
Word.run(async (context) => {
await Word.run(async (context) => {
var firstParagraph = context.document.body.paragraphs.getFirst();
firstParagraph.load("text");
await context.sync();
Expand All @@ -88,22 +86,9 @@ export const testWordEnd2End = async (testServerPort: number): Promise<void> =>
testValues.pop();
Promise.resolve();
});
} catch (error) {
testHelpers.addTestResult(testValues, "output-message", getErrorMessage(error), "");
await sendTestResults(testValues, testServerPort);
testValues.pop();
Promise.reject();
}
};

const getErrorMessage = (error: any): string => {
if (error instanceof Error) {
if ("stack" in error) {
return error.stack;
} else {
return `${error.name}: ${error.message}`;
}
} else {
return error;
} catch (err) {
testValues = [];
testHelpers.addErrorResult(testValues, `runTest failed: ${testHelpers.formatError(err)}`);
await sendTestResults(testValues, testServerPort).catch(() => {});
}
};
44 changes: 44 additions & 0 deletions test/end-to-end/src/test-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,50 @@ export function addTestResult(testValues: any[], resultName: string, resultValue
testValues.push(data);
}

export function addErrorResult(testValues: any[], errorMessage: string) {
testValues.push({
resultName: "test-error",
resultValue: errorMessage,
expectedValue: "no-error",
});
}

export function formatError(err: any): string {
if (!err) return "Unknown error (null/undefined)";

const parts: string[] = [];

// Basic message
if (err.message) {
parts.push(`Message: ${err.message}`);
} else {
parts.push(`${err}`);
}

// Office.js error code
if (err.code) {
parts.push(`Code: ${err.code}`);
}

// Office.js debugInfo (OfficeExtension.Error)
if (err.debugInfo) {
if (err.debugInfo.code) parts.push(`DebugCode: ${err.debugInfo.code}`);
if (err.debugInfo.message) parts.push(`DebugMessage: ${err.debugInfo.message}`);
if (err.debugInfo.errorLocation) parts.push(`Location: ${err.debugInfo.errorLocation}`);
if (err.debugInfo.innerError) {
const inner = err.debugInfo.innerError;
parts.push(`InnerError: ${inner.code || ""} ${inner.message || JSON.stringify(inner)}`);
}
}

// Stack trace
if (err.stack) {
parts.push(`Stack: ${err.stack}`);
}

return parts.join(" | ");
}

export async function sleep(ms: number): Promise<any> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
Expand Down
46 changes: 28 additions & 18 deletions test/end-to-end/src/test.index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import * as React from "react";
import { createRoot } from "react-dom/client";
import App from "../../../src/taskpane/components/App";
import { FluentProvider, webLightTheme } from "@fluentui/react-components";
import { pingTestServer } from "office-addin-test-helpers";
import { pingTestServer, sendTestResults } from "office-addin-test-helpers";
import { testExcelEnd2End, testPowerPointEnd2End, testWordEnd2End } from "./host-tests";
import * as testHelpers from "./test-helpers";

/* global document, Office, module, require */

Expand All @@ -16,26 +17,35 @@ const root = createRoot(rootElement);

/* Render application after Office initializes */
Office.onReady(async (info) => {
const testServerResponse: { status?: number } = await pingTestServer(port);
if (testServerResponse?.status === 200) {
//render(App);
root.render(
<FluentProvider theme={webLightTheme}>
<App title={title} />
</FluentProvider>
);
let testValues: any[] = [];
try {
Comment thread
millerds marked this conversation as resolved.
const testServerResponse: { status?: number } = await pingTestServer(port);
if (testServerResponse?.status === 200) {
//render(App);
root.render(
<FluentProvider theme={webLightTheme}>
<App title={title} />
</FluentProvider>
);

switch (info.host) {
case Office.HostType.Excel: {
return testExcelEnd2End(port);
}
case Office.HostType.PowerPoint: {
return testPowerPointEnd2End(port);
}
case Office.HostType.Word: {
return testWordEnd2End(port);
switch (info.host) {
case Office.HostType.Excel: {
return testExcelEnd2End(port);
}
case Office.HostType.PowerPoint: {
return testPowerPointEnd2End(port);
}
case Office.HostType.Word: {
return testWordEnd2End(port);
}
}
} else {
testHelpers.addErrorResult(testValues, `Ping failed: ${JSON.stringify(testServerResponse)}`);
await sendTestResults(testValues, port).catch(() => {});
}
} catch (err) {
testHelpers.addErrorResult(testValues, `Initialization failed: ${testHelpers.formatError(err)}`);
await sendTestResults(testValues, port).catch(() => {});
}
});

Expand Down
36 changes: 32 additions & 4 deletions test/end-to-end/ui-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as testHelpers from "./src/test-helpers";
const hosts = ["Excel", "PowerPoint", "Word"];
const manifestPath = path.resolve(`${process.cwd()}/test/end-to-end/test-manifest.xml`);
const testServerPort: number = 4201;
const testResultsTimeout: number = 120000; // 2 minutes to receive results before failing

hosts.forEach(function (host) {
const testServer = new officeAddinTestServer.TestServer(testServerPort);
Expand Down Expand Up @@ -39,14 +40,41 @@ hosts.forEach(function (host) {
}),
describe(`Get test results for ${host} taskpane project`, function () {
it("Validate expected result count", async function () {
this.timeout(0);
testValues = await testServer.getTestResults();
assert.strictEqual(testValues.length > 0, true);
this.timeout(testResultsTimeout + 10000);
let timeoutId!: ReturnType<typeof setTimeout>;
const timeoutPromise = new Promise<never>((_, reject) => {
timeoutId = setTimeout(
() =>
reject(
new Error(
`[${host}] Timed out after ${testResultsTimeout / 1000}s waiting for test results. ` +
`The add-in taskpane likely failed to initialize or encountered an unhandled error.`
)
),
testResultsTimeout
);
});

try {
testValues = await Promise.race([testServer.getTestResults(), timeoutPromise]);
} finally {
clearTimeout(timeoutId);
}

// Check if the taskpane reported an error
const errorResult = testValues.find((v: any) => v.resultName === "test-error");
if (errorResult) {
assert.fail(`[${host}] Taskpane reported error: ${errorResult.resultValue}`);
}

// Filter out error entries for actual result validation
testValues = testValues.filter((v: any) => v.resultName !== "test-error");
assert.strictEqual(testValues.length > 0, true, `No test results received from ${host} add-in`);
});
it("Validate expected result name", async function () {
assert.strictEqual(testValues[0].resultName, "output-message");
});
it("Validate expected result", async function () {
it("Validate expected result value", async function () {
assert.strictEqual(testValues[0].resultValue, testValues[0].expectedValue);
});
});
Expand Down
12 changes: 2 additions & 10 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
{
"compilerOptions": {
"allowUnusedLabels": false,
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"jsx": "react",
"module": "ES2020",
"moduleResolution": "node",
"moduleResolution": "bundler",
"noImplicitReturns": true,
"noUnusedParameters": true,
"outDir": "dist",
"removeComments": false,
"sourceMap": true,
"target": "es5",
"target": "es6",
"lib": [
"es7",
"dom"
],
"pretty": true,
"typeRoots": [
"node_modules/@types"
]
},
"exclude": [
"node_modules"
],
"compileOnSave": false,
"buildOnSave": false,
"ts-node": {
"compilerOptions": {
"module": "commonjs"
Expand Down