From 81029974b9f3366949f822e3ad194b60b2214a3d Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Sun, 16 Nov 2025 11:58:34 -0500 Subject: [PATCH 01/14] front end in prog , not working --- .../components/panel/editor/EditorPanel.tsx | 47 ++++++++++- .../panel/editor/tab/TestResultTab.tsx | 83 +++++++++++++++++++ .../src/components/panel/editor/tab/index.ts | 1 + extension/src/store/roomStore.ts | 41 ++++++++- extension/src/types/index.ts | 15 ++++ extension/src/types/peers.ts | 2 + extension/src/utils/messages.ts | 9 ++ 7 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 extension/src/components/panel/editor/tab/TestResultTab.tsx diff --git a/extension/src/components/panel/editor/EditorPanel.tsx b/extension/src/components/panel/editor/EditorPanel.tsx index b866e6c5..10f78fd4 100644 --- a/extension/src/components/panel/editor/EditorPanel.tsx +++ b/extension/src/components/panel/editor/EditorPanel.tsx @@ -1,6 +1,10 @@ import { UserDropDownMenu } from "@cb/components/navigator/menu/UserDropDownMenu"; import CreateRoomLoadingPanel from "@cb/components/panel/editor/CreateRoomLoadingPanel"; -import { CodeTab, TestTab } from "@cb/components/panel/editor/tab"; +import { + CodeTab, + TestResultTab, + TestTab, +} from "@cb/components/panel/editor/tab"; import { Tooltip } from "@cb/components/tooltip"; import { SkeletonWrapper } from "@cb/components/ui/SkeletonWrapper"; import { useCopyCode } from "@cb/hooks/editor"; @@ -27,7 +31,8 @@ const EditorPanel = () => { const { selectedPeer, peers } = usePeers(); const { self } = useRoomData(); const roomStatus = useRoomStatus(); - const { selectTest, toggleCodeVisibility } = usePeerActions(); + const { selectTest, selectTestResult, toggleCodeVisibility } = + usePeerActions(); const { getLanguageExtension } = useLeetCodeActions(); const copyCode = useCopyCode(); @@ -37,9 +42,26 @@ const EditorPanel = () => { ); const emptyRoom = Object.keys(peers).length === 0; + // const activeTestResult = selectedPeer?.questions[url]?.testResults.find( + // (testResult) => testResult.selected + // ); + + // placeholder until we have real test results (moved into useMemo to satisfy hook deps) + const upperTabConfigs = React.useMemo(() => { const extension = getLanguageExtension(selectedPeer?.questions[url]?.code?.language) ?? ""; + const activeTestResult = activeTest + ? { + selected: true, + testResult: activeTest.test.map((a) => ({ + variable: a.variable, + value: a.value, + output: a.value, + expected: a.value, + })), + } + : undefined; return [ { value: "code", @@ -59,8 +81,27 @@ const EditorPanel = () => { /> ), }, + { + value: "testResult", + label: "Test Result", + Icon: FlaskConical, + Content: ( + + ), + }, ]; - }, [selectedPeer, activeTest, selectTest, getLanguageExtension, url]); + }, [ + selectedPeer, + activeTest, + selectTest, + selectTestResult, + getLanguageExtension, + url, + ]); const hideCode = !selectedPeer?.questions[self?.url ?? ""]?.viewable; diff --git a/extension/src/components/panel/editor/tab/TestResultTab.tsx b/extension/src/components/panel/editor/tab/TestResultTab.tsx new file mode 100644 index 00000000..bf787b4b --- /dev/null +++ b/extension/src/components/panel/editor/tab/TestResultTab.tsx @@ -0,0 +1,83 @@ +import { SkeletonWrapper } from "@cb/components/ui/SkeletonWrapper"; +import { useRoomData } from "@cb/hooks/store"; +import { Identifiable, PeerState, SelectableTestResult } from "@cb/types"; +import React from "react"; + +interface TestResultTabProps { + activePeer: Identifiable | undefined; + activeTestResult: SelectableTestResult | undefined; + selectTestResult: (index: number) => void; +} + +export const TestResultTab: React.FC = ({ + activePeer, + activeTestResult, + selectTestResult, +}) => { + console.log("activeTestResult", activeTestResult); + const { self } = useRoomData(); + return ( + +
+
+
+ {(activePeer?.questions[self?.url ?? ""]?.tests ?? []).map( + (test, idx) => ( +
selectTestResult(idx)}> + {test.selected ? ( + + ) : ( + + )} +
+ ) + )} +
+
+
+
+
+ {activeTestResult?.testResult.map((assignment, idx) => ( + + {/* Input / Value */} +
+ Input +
+
+
+ {assignment.variable} = {assignment.value} +
+
+ + {/* Output */} +
+ Output +
+
+
+ {assignment.output ?? "-"} +
+
+ + {/* Expected */} +
+ Expected +
+
+
+ {assignment.expected ?? "-"} +
+
+
+ )) ?? null} +
+
+
+
+
+ ); +}; diff --git a/extension/src/components/panel/editor/tab/index.ts b/extension/src/components/panel/editor/tab/index.ts index 817b43f3..1e577d9a 100644 --- a/extension/src/components/panel/editor/tab/index.ts +++ b/extension/src/components/panel/editor/tab/index.ts @@ -1,2 +1,3 @@ export { CodeTab } from "@cb/components/panel/editor/tab/CodeTab"; +export { TestResultTab } from "@cb/components/panel/editor/tab/TestResultTab"; export { TestTab } from "@cb/components/panel/editor/tab/TestTab"; diff --git a/extension/src/store/roomStore.ts b/extension/src/store/roomStore.ts index adb0e6ef..ad7b53ba 100644 --- a/extension/src/store/roomStore.ts +++ b/extension/src/store/roomStore.ts @@ -17,6 +17,7 @@ import { SelfState, Slug, TestCases, + TestResults, User, } from "@cb/types"; import { Identifiable } from "@cb/types/utils"; @@ -47,6 +48,7 @@ export enum RoomStatus { interface UpdatePeerQuestionProgress { code?: CodeWithChanges; tests?: TestCases; + testResults?: TestResults; status?: QuestionProgressStatus; } @@ -101,6 +103,7 @@ interface RoomAction { remove: (ids: Id[]) => void; selectPeer: (id: string) => void; selectTest: (idx: number) => void; + selectTestResult: (idx: number) => void; toggleCodeVisibility: () => void; }; self: { @@ -157,10 +160,16 @@ const createRoomStore = (background: BackgroundProxy, appStore: AppStore) => { (acc, curr) => { const [url, data] = curr; const normalizedUrl = getNormalizedUrl(url); - const { code, tests: testsPayload, status } = data; + const { + code, + tests: testsPayload, + testResults: testResultsPayload, + status, + } = data; const questionProgressOrDefault = state.questions[normalizedUrl] ?? { code: undefined, tests: [], + testResults: [], status: QuestionProgressStatus.NOT_STARTED, viewable: false, }; @@ -186,6 +195,25 @@ const createRoomStore = (background: BackgroundProxy, appStore: AppStore) => { questionProgressOrDefault.tests = tests; } + if (testResultsPayload != undefined) { + const testResults = testResultsPayload.map((testResult) => ({ + ...testResult, + selected: false, + })); + const previousSelectedTest = + questionProgressOrDefault.testResults.findIndex( + (testResult) => testResult.selected + ); + const selectedTestIndex = + previousSelectedTest >= testResults.length + ? testResults.length - 1 + : Math.max(previousSelectedTest, 0); + if (testResults[selectedTestIndex] != undefined) { + testResults[selectedTestIndex].selected = true; + } + questionProgressOrDefault.testResults = testResults; + } + if (status != undefined) { questionProgressOrDefault.status = status; } @@ -207,9 +235,20 @@ const createRoomStore = (background: BackgroundProxy, appStore: AppStore) => { }; }; + //define a dummy function getTestResultsPayload with this type const getTestsPayload: (variables: { + // count: number; + // names: string[]; + // } | undefined) => PeerTestMessage + const getTestResultsPayload = (variables: Variable[]) => { + return { + testResults: [], + }; + }; + const setSelfProgressForCurrentUrl = async (question: Question) => { const code = await background.getCode({}); const { tests } = getTestsPayload(question.variables); + const { testResults } = getTestResultsPayload(question.variables); useRoom.getState().actions.self.update({ questions: { [question.url]: { diff --git a/extension/src/types/index.ts b/extension/src/types/index.ts index 7f92ef4e..dac3c1b1 100644 --- a/extension/src/types/index.ts +++ b/extension/src/types/index.ts @@ -15,14 +15,29 @@ interface Assignment { value: string; } +interface ResultAssignment { + variable?: string; + value: string; + output: string; + expected: string; +} + export interface TestCase { test: Assignment[]; } +export interface TestResult { + testResult: ResultAssignment[]; +} + export type TestCases = TestCase[]; +export type TestResults = TestResult[]; + export interface SelectableTestCase extends TestCase, Selectable {} +export interface SelectableTestResult extends TestResult, Selectable {} + // Refactor post redux export interface LocalStorage { signIn: { diff --git a/extension/src/types/peers.ts b/extension/src/types/peers.ts index 94f6c24d..a27035dc 100644 --- a/extension/src/types/peers.ts +++ b/extension/src/types/peers.ts @@ -2,6 +2,7 @@ import { Id, QuestionProgressStatus, SelectableTestCase, + SelectableTestResult, TestCase, TestCases, } from "."; @@ -72,6 +73,7 @@ export type PeerMessage = interface PeerQuestionProgress { code?: CodeWithChanges; tests: SelectableTestCase[]; + testResults: SelectableTestResult[]; status: QuestionProgressStatus; viewable: boolean; } diff --git a/extension/src/utils/messages.ts b/extension/src/utils/messages.ts index b7caa0bc..26061a20 100644 --- a/extension/src/utils/messages.ts +++ b/extension/src/utils/messages.ts @@ -17,6 +17,15 @@ export const getTestsPayload = ( }; }; +export const getTestResultsPayload = ( + variables: { count: number; names: string[] } | undefined +) => { + return { + testResults: [], + status: "ok", + }; +}; + export const getCodePayload = async ( changes: Partial ): Promise> => { From e984708721872172e3ceb24ece95c014b69ba0aa Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Sun, 23 Nov 2025 21:56:53 -0500 Subject: [PATCH 02/14] backend in progress --- .../navigator/menu/UserDropDownMenu.tsx | 3 + .../components/panel/editor/EditorPanel.tsx | 20 +----- .../panel/editor/tab/TestResultTab.tsx | 2 +- extension/src/constants/index.ts | 1 + extension/src/hooks/toasts/index.ts | 10 +++ .../services/controllers/MessageDispatcher.ts | 56 ++++++++++++++++- extension/src/store/roomStore.ts | 29 +++++---- extension/src/types/db.ts | 1 + extension/src/types/index.ts | 3 +- extension/src/types/peers.ts | 23 ++++++- extension/src/utils/messages.ts | 62 +++++++++++++++++-- 11 files changed, 172 insertions(+), 38 deletions(-) diff --git a/extension/src/components/navigator/menu/UserDropDownMenu.tsx b/extension/src/components/navigator/menu/UserDropDownMenu.tsx index 5a111843..05700462 100644 --- a/extension/src/components/navigator/menu/UserDropDownMenu.tsx +++ b/extension/src/components/navigator/menu/UserDropDownMenu.tsx @@ -27,6 +27,9 @@ const STATUS_ICON_MAP: Record = { [QuestionProgressStatus.IN_PROGRESS]: ( ), + [QuestionProgressStatus.RUN_TEST]: ( + + ), [QuestionProgressStatus.COMPLETED]: ( ), diff --git a/extension/src/components/panel/editor/EditorPanel.tsx b/extension/src/components/panel/editor/EditorPanel.tsx index 10f78fd4..3e74e31d 100644 --- a/extension/src/components/panel/editor/EditorPanel.tsx +++ b/extension/src/components/panel/editor/EditorPanel.tsx @@ -42,26 +42,12 @@ const EditorPanel = () => { ); const emptyRoom = Object.keys(peers).length === 0; - // const activeTestResult = selectedPeer?.questions[url]?.testResults.find( - // (testResult) => testResult.selected - // ); - - // placeholder until we have real test results (moved into useMemo to satisfy hook deps) - const upperTabConfigs = React.useMemo(() => { const extension = getLanguageExtension(selectedPeer?.questions[url]?.code?.language) ?? ""; - const activeTestResult = activeTest - ? { - selected: true, - testResult: activeTest.test.map((a) => ({ - variable: a.variable, - value: a.value, - output: a.value, - expected: a.value, - })), - } - : undefined; + const activeTestResult = selectedPeer?.questions[url]?.testResults.find( + (testResult) => testResult.selected + ); return [ { value: "code", diff --git a/extension/src/components/panel/editor/tab/TestResultTab.tsx b/extension/src/components/panel/editor/tab/TestResultTab.tsx index bf787b4b..6db683c4 100644 --- a/extension/src/components/panel/editor/tab/TestResultTab.tsx +++ b/extension/src/components/panel/editor/tab/TestResultTab.tsx @@ -49,7 +49,7 @@ export const TestResultTab: React.FC = ({
- {assignment.variable} = {assignment.value} + {assignment.input}
diff --git a/extension/src/constants/index.ts b/extension/src/constants/index.ts index 2132b78d..0526ce77 100644 --- a/extension/src/constants/index.ts +++ b/extension/src/constants/index.ts @@ -13,6 +13,7 @@ export const DOM = { IFRAME_CSS_ID: "codebuddy-css", LEETCODE_ROOT_ID: "#qd-content", LEETCODE_TEST_ID: ".cm-content", + LEETCODE_RUN_TEST_RESULT: '[data-e2e-locator="console-result"]', LEETCODE_SUBMIT_BUTTON: '[data-e2e-locator="console-submit-button"]', LEETCODE_SUBMISSION_RESULT: '[data-e2e-locator="submission-result"]', PROBLEM_ID: ".elfjS", diff --git a/extension/src/hooks/toasts/index.ts b/extension/src/hooks/toasts/index.ts index b63759a8..728ad9c3 100644 --- a/extension/src/hooks/toasts/index.ts +++ b/extension/src/hooks/toasts/index.ts @@ -39,6 +39,16 @@ export const useToast = () => { } const { event, user } = message; switch (event) { + case EventType.RUN_TEST_SUCCESS: { + toast.info(`${user} passed all customizable test cases`); + break; + } + + case EventType.RUN_TEST_FAILURE: { + toast.info(`${user} failed some customizable test cases`); + break; + } + case EventType.SUBMIT_SUCCESS: { toast.info(`${user} passed all test cases`); break; diff --git a/extension/src/services/controllers/MessageDispatcher.ts b/extension/src/services/controllers/MessageDispatcher.ts index a13165ae..b34445e2 100644 --- a/extension/src/services/controllers/MessageDispatcher.ts +++ b/extension/src/services/controllers/MessageDispatcher.ts @@ -69,6 +69,7 @@ export class MessageDispatcher { this.unsubscribers.push(this.subscribeToCodeEditor()); this.unsubscribers.push(this.subscribeToTestEditor()); + this.unsubscribers.push(this.subscribeToRunTest()); this.unsubscribers.push(this.subscribeToRtcOpen()); this.unsubscribers.push(this.subscribeToRtcMessage()); this.unsubscribers.push(this.subscribeToRoomChanges()); @@ -152,8 +153,40 @@ export class MessageDispatcher { return () => observer.disconnect(); } + private subscribeToRunTest() { + const observer = new MutationObserver(async () => { + const testResult = await this.getTestResultPayload(); + this.roomStore.getState().actions.self.update({ + questions: { + [testResult.url]: { + testResults: testResult.testResults, + }, + }, + }); + console.log("Emitting test result -- message dispatcher", testResult); + this.emitter.emit("rtc.send.message", { + message: testResult, + }); + }); + waitForElement(DOM.LEETCODE_RUN_TEST_RESULT) + .then((editor) => { + console.log("Observing test result editor -- change happened?", editor); + observer.observe(editor, { + attributes: true, + childList: true, + subtree: true, + }); + }) + .catch(() => + console.error( + "Unable to find test result", + DOM.LEETCODE_RUN_TEST_RESULT + ) + ); + return () => observer.disconnect(); + } + private subscribeToSubmission() { - // todo(nickbar01234): On teardown, we need to revert the changes const sendSuccessSubmission = () => { if (this.appStore.getState().auth.status === AppStatus.AUTHENTICATED) { const url = getNormalizedUrl(window.location.href); @@ -246,6 +279,19 @@ export class MessageDispatcher { break; } + case "testResults": { + const { testResults, url } = message; + this.roomStore.getState().actions.peers.update(from, { + questions: { + [url]: { + testResults, + status: QuestionProgressStatus.RUN_TEST, + }, + }, + }); + break; + } + case "event": { const { url, event } = message; if (event === EventType.SUBMIT_SUCCESS) { @@ -378,4 +424,12 @@ export class MessageDispatcher { .actions.room.getVariables(getNormalizedUrl(window.location.href)) ); } + + private getTestResultPayload() { + return getTestResultsPayload( + this.roomStore + .getState() + .actions.room.getVariables(getNormalizedUrl(window.location.href)) + ); + } } diff --git a/extension/src/store/roomStore.ts b/extension/src/store/roomStore.ts index ad7b53ba..a908cbfc 100644 --- a/extension/src/store/roomStore.ts +++ b/extension/src/store/roomStore.ts @@ -235,25 +235,16 @@ const createRoomStore = (background: BackgroundProxy, appStore: AppStore) => { }; }; - //define a dummy function getTestResultsPayload with this type const getTestsPayload: (variables: { - // count: number; - // names: string[]; - // } | undefined) => PeerTestMessage - const getTestResultsPayload = (variables: Variable[]) => { - return { - testResults: [], - }; - }; - const setSelfProgressForCurrentUrl = async (question: Question) => { const code = await background.getCode({}); const { tests } = getTestsPayload(question.variables); - const { testResults } = getTestResultsPayload(question.variables); + // const { testResults } = getTestResultsPayload(question.variables); useRoom.getState().actions.self.update({ questions: { [question.url]: { code, tests, + // testResults, }, }, }); @@ -512,6 +503,22 @@ const createRoomStore = (background: BackgroundProxy, appStore: AppStore) => { })); } }), + selectTestResult: (idx) => + set((state) => { + const active = getSelectedPeer(state.peers); + const progress = + state.peers[active?.id ?? ""].questions[ + getNormalizedUrl(window.location.href) + ]; + if (progress != undefined) { + progress.testResults = progress.testResults.map( + (test, i) => ({ + ...test, + selected: i === idx, + }) + ); + } + }), toggleCodeVisibility: () => set((state) => { const active = getSelectedPeer(state.peers); diff --git a/extension/src/types/db.ts b/extension/src/types/db.ts index dc42ff7f..0abbc84d 100644 --- a/extension/src/types/db.ts +++ b/extension/src/types/db.ts @@ -37,6 +37,7 @@ type NegotiationMessage = export enum QuestionProgressStatus { NOT_STARTED = "not-started", IN_PROGRESS = "in-progress", + RUN_TEST = "run-test", COMPLETED = "completed", } diff --git a/extension/src/types/index.ts b/extension/src/types/index.ts index dac3c1b1..90481e40 100644 --- a/extension/src/types/index.ts +++ b/extension/src/types/index.ts @@ -16,8 +16,7 @@ interface Assignment { } interface ResultAssignment { - variable?: string; - value: string; + input: string; output: string; expected: string; } diff --git a/extension/src/types/peers.ts b/extension/src/types/peers.ts index a27035dc..1d6cb115 100644 --- a/extension/src/types/peers.ts +++ b/extension/src/types/peers.ts @@ -5,6 +5,8 @@ import { SelectableTestResult, TestCase, TestCases, + TestResult, + TestResults, } from "."; import type { ServiceResponse } from "./services"; import { GenericMessage, Selectable } from "./utils"; @@ -25,6 +27,11 @@ interface PeerCodeMessage extends PeerGenericMessage, CodeWithChanges { action: "code"; } +interface PeerTestResultMessage extends PeerGenericMessage { + action: "testResults"; + testResults: TestResults; +} + interface PeerTestMessage extends PeerGenericMessage { action: "tests"; tests: TestCases; @@ -41,6 +48,8 @@ interface SendProgressMessage extends PeerGenericMessage { } export enum EventType { + RUN_TEST_SUCCESS, + RUN_TEST_FAILURE, SUBMIT_SUCCESS, SUBMIT_FAILURE, ADD_QUESTION, @@ -52,6 +61,10 @@ interface PeerGenericEventMessage extends PeerGenericMessage { user: Id; } +interface PeerEventRunTestMesage extends PeerGenericEventMessage { + event: EventType.RUN_TEST_SUCCESS | EventType.RUN_TEST_FAILURE; +} + interface PeerEventSubmissionMesage extends PeerGenericEventMessage { event: EventType.SUBMIT_SUCCESS | EventType.SUBMIT_FAILURE; } @@ -61,14 +74,19 @@ interface PeerEventAddQuestionMessage extends PeerGenericEventMessage { question: string; } -type PeerEventMessage = PeerEventSubmissionMesage | PeerEventAddQuestionMessage; +type PeerEventMessage = + | PeerEventRunTestMesage + | PeerEventSubmissionMesage + | PeerEventAddQuestionMessage; export type PeerMessage = | PeerCodeMessage | PeerTestMessage + | PeerTestResultMessage | PeerEventMessage | RequestProgressMessage - | SendProgressMessage; + | SendProgressMessage + | PeerEventRunTestMesage; interface PeerQuestionProgress { code?: CodeWithChanges; @@ -81,6 +99,7 @@ interface PeerQuestionProgress { interface SelfQuestionProgress { code?: MonacoCode; tests: TestCase[]; + testResults?: TestResult[]; status: QuestionProgressStatus; } diff --git a/extension/src/utils/messages.ts b/extension/src/utils/messages.ts index 26061a20..211944fd 100644 --- a/extension/src/utils/messages.ts +++ b/extension/src/utils/messages.ts @@ -17,12 +17,66 @@ export const getTestsPayload = ( }; }; +// not done with this at all export const getTestResultsPayload = ( - variables: { count: number; names: string[] } | undefined -) => { + variables: Question["variables"] | undefined +): ExtractMessage => { + // --------------------- + // Extract all test case blocks + // --------------------- + + const statusText = + document + .querySelector( + ".text-xl.font-medium.text-red-s, .text-xl.font-medium.text-green-s" + ) + ?.textContent?.trim() ?? "Unknown Status"; + + // Helper to extract all text under a label (Input/Output/Expected) + const extractBlocks = (label: string) => { + return Array.from( + document.querySelectorAll(".flex.flex-col .text-xs.font-medium") + ) + .filter((el) => el.textContent?.trim() === label) + .map((labelEl) => { + const cmContent = + labelEl.parentElement?.parentElement?.querySelector(".cm-content"); + return cmContent?.textContent?.trim() ?? ""; + }); + }; + + const inputs = extractBlocks("Input"); + const outputs = extractBlocks("Output"); + const expecteds = extractBlocks("Expected"); + + // --------------------- + // Combine into a list of test cases + // --------------------- + + const testResults = []; + + const maxCases = Math.max(inputs.length, outputs.length, expecteds.length); + + for (let i = 0; i < maxCases; i++) { + //check to fix this again + const resultAssignment = { + input: inputs[i] ?? "", + output: outputs[i] ?? "", + expected: expecteds[i] ?? "", + }; + testResults.push({ + testResult: [resultAssignment], + }); + } + + // --------------------- + // Return payload + // --------------------- + return { - testResults: [], - status: "ok", + action: "testResults", + testResults: testResults, + url: getNormalizedUrl(window.location.href), }; }; From 406e8b1c122615aa0c4f159c3af23accb10014db Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Tue, 25 Nov 2025 14:08:05 -0500 Subject: [PATCH 03/14] fix scraping from leetcode --- extension/src/constants/index.ts | 2 +- .../services/controllers/MessageDispatcher.ts | 97 +++++++++---- extension/src/utils/messages.ts | 133 +++++++++++------- extension/src/utils/string.ts | 33 ++++- 4 files changed, 188 insertions(+), 77 deletions(-) diff --git a/extension/src/constants/index.ts b/extension/src/constants/index.ts index 0526ce77..166a578c 100644 --- a/extension/src/constants/index.ts +++ b/extension/src/constants/index.ts @@ -13,7 +13,7 @@ export const DOM = { IFRAME_CSS_ID: "codebuddy-css", LEETCODE_ROOT_ID: "#qd-content", LEETCODE_TEST_ID: ".cm-content", - LEETCODE_RUN_TEST_RESULT: '[data-e2e-locator="console-result"]', + LEETCODE_RUN_TEST_RESULT: ".cm-content", LEETCODE_SUBMIT_BUTTON: '[data-e2e-locator="console-submit-button"]', LEETCODE_SUBMISSION_RESULT: '[data-e2e-locator="submission-result"]', PROBLEM_ID: ".elfjS", diff --git a/extension/src/services/controllers/MessageDispatcher.ts b/extension/src/services/controllers/MessageDispatcher.ts index b34445e2..74772a0e 100644 --- a/extension/src/services/controllers/MessageDispatcher.ts +++ b/extension/src/services/controllers/MessageDispatcher.ts @@ -153,37 +153,82 @@ export class MessageDispatcher { return () => observer.disconnect(); } - private subscribeToRunTest() { - const observer = new MutationObserver(async () => { - const testResult = await this.getTestResultPayload(); - this.roomStore.getState().actions.self.update({ - questions: { - [testResult.url]: { - testResults: testResult.testResults, - }, - }, - }); - console.log("Emitting test result -- message dispatcher", testResult); - this.emitter.emit("rtc.send.message", { - message: testResult, - }); - }); - waitForElement(DOM.LEETCODE_RUN_TEST_RESULT) - .then((editor) => { - console.log("Observing test result editor -- change happened?", editor); - observer.observe(editor, { - attributes: true, - childList: true, - subtree: true, - }); + // private subscribeToRunTest() { + // const observer = new MutationObserver(async () => { + // console.log("Detected run test mutation"); + // const testResult = await this.getTestResultPayload(); + // this.roomStore.getState().actions.self.update({ + // questions: { + // [testResult.url]: { + // testResults: testResult.testResults, + // }, + // }, + // }); + // console.log("Emitting test result -- message dispatcher", testResult); + // this.emitter.emit("rtc.send.message", { + // message: testResult, + // }); + // }); + // waitForElement(DOM.LEETCODE_RUN_TEST_RESULT) + // .then((editor) => { + // console.log("Observing test result editor -- change happened yet 2?", editor); + // observer.observe(editor, { + // attributes: true, + // childList: true, + // subtree: true, + // characterData: true, + // }); + // }) + // .catch(() => + // console.error( + // "Unable to find test result", + // DOM.LEETCODE_RUN_TEST_RESULT + // ) + // ); + // return () => observer.disconnect(); + // } + + private subscribeToRunTest(): () => void { + let cleanup = () => {}; + + waitForElement('[data-e2e-locator="console-run-button"]') + .then((runButton) => { + console.log("Found Run button:", runButton); + + const clickHandler = async () => { + console.log("Detected run test via button click"); + const testResult = await this.getTestResultPayload(); + + // Update the store + this.roomStore.getState().actions.self.update({ + questions: { + [testResult.url]: { + testResults: testResult.testResults, + }, + }, + }); + + console.log("Emitting test result -- message dispatcher", testResult); + this.emitter.emit("rtc.send.message", { + message: testResult, + }); + }; + + // Attach the click listener + runButton.addEventListener("click", clickHandler); + + // Set the cleanup function + cleanup = () => runButton.removeEventListener("click", clickHandler); }) .catch(() => console.error( - "Unable to find test result", - DOM.LEETCODE_RUN_TEST_RESULT + "Unable to find Run button", + '[data-e2e-locator="console-run-button"]' ) ); - return () => observer.disconnect(); + + // Return cleanup function immediately + return cleanup; } private subscribeToSubmission() { diff --git a/extension/src/utils/messages.ts b/extension/src/utils/messages.ts index 211944fd..9f81fe6d 100644 --- a/extension/src/utils/messages.ts +++ b/extension/src/utils/messages.ts @@ -17,68 +17,103 @@ export const getTestsPayload = ( }; }; -// not done with this at all export const getTestResultsPayload = ( variables: Question["variables"] | undefined ): ExtractMessage => { - // --------------------- - // Extract all test case blocks - // --------------------- + const testResults = Array.from( + document.querySelectorAll(DOM.LEETCODE_TEST_ID) + ); - const statusText = - document - .querySelector( - ".text-xl.font-medium.text-red-s, .text-xl.font-medium.text-green-s" - ) - ?.textContent?.trim() ?? "Unknown Status"; + console.log("testResults", testResults); - // Helper to extract all text under a label (Input/Output/Expected) - const extractBlocks = (label: string) => { - return Array.from( - document.querySelectorAll(".flex.flex-col .text-xs.font-medium") - ) - .filter((el) => el.textContent?.trim() === label) - .map((labelEl) => { - const cmContent = - labelEl.parentElement?.parentElement?.querySelector(".cm-content"); - return cmContent?.textContent?.trim() ?? ""; - }); + const testInputs = [...(testResults[0]?.children ?? [])].map( + (line) => (line as HTMLElement).innerText + ); + const testOutputs = [...(testResults[1]?.children ?? [])].map( + (line) => (line as HTMLElement).innerText + ); + const testExpectedOutputs = [...(testResults[2]?.children ?? [])].map( + (line) => (line as HTMLElement).innerText + ); + + console.log("testInputs", testInputs); + console.log("testOutputs", testOutputs); + console.log("testExpectedOutputs", testExpectedOutputs); + + return { + action: "testResults", + testResults: groupTestResults( + variables, + testInputs, + testOutputs, + testExpectedOutputs + ), + url: getNormalizedUrl(window.location.href), }; +}; - const inputs = extractBlocks("Input"); - const outputs = extractBlocks("Output"); - const expecteds = extractBlocks("Expected"); +// export const getTestResultsPayload = (variables: Question["variables"] | undefined): ExtractMessage => { +// // --------------------- +// // Extract overall status +// // --------------------- +// const statusText = +// document +// .querySelector('[data-e2e-locator="console-result"]') +// ?.textContent?.trim() ?? "Unknown Status"; - // --------------------- - // Combine into a list of test cases - // --------------------- +// // --------------------- +// // Helper: extract text blocks per label +// // --------------------- +// const extractBlocks = (label: string) => { +// const labels = Array.from( +// document.querySelectorAll(".flex.flex-col .text-xs.font-medium") +// ).filter((el) => el.textContent?.trim() === label); - const testResults = []; +// return labels.map((labelEl) => { +// // `.cm-content` inside the same parent hierarchy +// const cmContent = +// labelEl.parentElement?.parentElement?.querySelectorAll(".cm-content"); +// if (!cmContent) return ""; - const maxCases = Math.max(inputs.length, outputs.length, expecteds.length); +// // Combine all lines inside cm-content +// return Array.from(cmContent) +// .map((div) => div.textContent?.trim()) +// .filter(Boolean) +// .join("\n"); +// }); +// }; - for (let i = 0; i < maxCases; i++) { - //check to fix this again - const resultAssignment = { - input: inputs[i] ?? "", - output: outputs[i] ?? "", - expected: expecteds[i] ?? "", - }; - testResults.push({ - testResult: [resultAssignment], - }); - } +// const inputs = extractBlocks("Input"); +// const outputs = extractBlocks("Output"); +// const expecteds = extractBlocks("Expected"); - // --------------------- - // Return payload - // --------------------- +// // --------------------- +// // Combine into testResults array +// // --------------------- +// const testResults = []; +// const maxCases = Math.max(inputs.length, outputs.length, expecteds.length); - return { - action: "testResults", - testResults: testResults, - url: getNormalizedUrl(window.location.href), - }; -}; +// for (let i = 0; i < maxCases; i++) { +// testResults.push({ +// testResult: [ +// { +// input: inputs[i] ?? "", +// output: outputs[i] ?? "", +// expected: expecteds[i] ?? "", +// }, +// ], +// }); +// } + +// // --------------------- +// // Return payload +// // --------------------- +// return { +// action: "testResults", +// testResults, +// url: getNormalizedUrl(window.location.href), +// }; +// }; export const getCodePayload = async ( changes: Partial diff --git a/extension/src/utils/string.ts b/extension/src/utils/string.ts index 6da34db2..ee9c200f 100644 --- a/extension/src/utils/string.ts +++ b/extension/src/utils/string.ts @@ -1,4 +1,4 @@ -import { Question, TestCase } from "@cb/types"; +import { Question, TestCase, TestResult } from "@cb/types"; export const capitalize = (str: string | undefined) => str ? str.charAt(0).toUpperCase() + str.slice(1) : ""; @@ -28,6 +28,37 @@ export const groupTestCases = ( })); }; +export const groupTestResults = ( + variables: Question["variables"] | undefined, + testInputs: string[], + testOutputs: string[], + testExpectedOutputs: string[] +): TestResult[] => { + console.log("testResults", testInputs); + if (variables == undefined || testInputs.length % variables.count !== 0) { + console.error( + "Variables are undefined or tests do not match up", + variables, + testInputs + ); + return []; + } + + const chunks = testInputs.length / variables.count; + const groups = Array.from({ length: chunks }, (_, idx) => + testInputs.slice(idx * variables.count, (idx + 1) * variables.count) + ); + return groups.map((group) => ({ + testResult: group.map((assignment, idx) => ({ + variable: variables.names[idx], + value: assignment, + input: assignment, + output: assignment, // Placeholder until we parse properly + expected: assignment, // Placeholder until we parse properly + })), + })); +}; + export const safeJsonParse = (content: string): object => { try { return JSON.parse(content); From d6646e926ac66c4ad699d42d677454f613bd5f12 Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Tue, 25 Nov 2025 22:59:26 -0500 Subject: [PATCH 04/14] commit to keep progress --- .../panel/editor/tab/TestResultTab.tsx | 2 +- .../services/controllers/MessageDispatcher.ts | 72 +++++++++++++------ extension/src/types/index.ts | 2 +- extension/src/utils/messages.ts | 65 +---------------- extension/src/utils/string.ts | 70 ++++++++++++------ 5 files changed, 103 insertions(+), 108 deletions(-) diff --git a/extension/src/components/panel/editor/tab/TestResultTab.tsx b/extension/src/components/panel/editor/tab/TestResultTab.tsx index 6db683c4..a5b7a3b4 100644 --- a/extension/src/components/panel/editor/tab/TestResultTab.tsx +++ b/extension/src/components/panel/editor/tab/TestResultTab.tsx @@ -49,7 +49,7 @@ export const TestResultTab: React.FC = ({
- {assignment.input} + {String(assignment.input ?? "-")}
diff --git a/extension/src/services/controllers/MessageDispatcher.ts b/extension/src/services/controllers/MessageDispatcher.ts index 74772a0e..c1b29b2e 100644 --- a/extension/src/services/controllers/MessageDispatcher.ts +++ b/extension/src/services/controllers/MessageDispatcher.ts @@ -191,33 +191,66 @@ export class MessageDispatcher { private subscribeToRunTest(): () => void { let cleanup = () => {}; + // Attach click handler to the run button. On click, wait for the + // console-result element to appear/change, then scrape and emit. waitForElement('[data-e2e-locator="console-run-button"]') .then((runButton) => { - console.log("Found Run button:", runButton); - const clickHandler = async () => { - console.log("Detected run test via button click"); - const testResult = await this.getTestResultPayload(); + try { + // Wait for the result container to exist in the DOM + const resultEl = await waitForElement(DOM.LEETCODE_RUN_TEST_RESULT); + + // Wait for the next meaningful mutation inside the result container. + await new Promise((resolve, reject) => { + const observer = new MutationObserver(() => { + // If the container now has text or children, assume results are present. + const hasContent = + (resultEl.textContent ?? "").trim().length > 0 || + resultEl.children.length > 0; + if (hasContent) { + observer.disconnect(); + clearTimeout(timeout); + resolve(); + } + }); + + observer.observe(resultEl, { + childList: true, + subtree: true, + characterData: true, + }); + + const timeout = setTimeout(() => { + observer.disconnect(); + reject(new Error("Timed out waiting for test result mutation")); + }, DOM.TIMEOUT); + }).catch((err) => { + console.warn("Timed out waiting for test result mutation", err); + }); - // Update the store - this.roomStore.getState().actions.self.update({ - questions: { - [testResult.url]: { - testResults: testResult.testResults, + const testResult = await this.getTestResultPayload(); + + this.roomStore.getState().actions.self.update({ + questions: { + [testResult.url]: { + testResults: testResult.testResults, + }, }, - }, - }); + }); - console.log("Emitting test result -- message dispatcher", testResult); - this.emitter.emit("rtc.send.message", { - message: testResult, - }); + console.log( + "Emitting test result -- message dispatcher", + testResult + ); + this.emitter.emit("rtc.send.message", { + message: testResult, + }); + } catch (e) { + console.error("Error handling run button click", e); + } }; - // Attach the click listener runButton.addEventListener("click", clickHandler); - - // Set the cleanup function cleanup = () => runButton.removeEventListener("click", clickHandler); }) .catch(() => @@ -227,8 +260,7 @@ export class MessageDispatcher { ) ); - // Return cleanup function immediately - return cleanup; + return () => cleanup(); } private subscribeToSubmission() { diff --git a/extension/src/types/index.ts b/extension/src/types/index.ts index 90481e40..e4efee17 100644 --- a/extension/src/types/index.ts +++ b/extension/src/types/index.ts @@ -16,7 +16,7 @@ interface Assignment { } interface ResultAssignment { - input: string; + input: Record; output: string; expected: string; } diff --git a/extension/src/utils/messages.ts b/extension/src/utils/messages.ts index 9f81fe6d..a10c63bd 100644 --- a/extension/src/utils/messages.ts +++ b/extension/src/utils/messages.ts @@ -43,7 +43,7 @@ export const getTestResultsPayload = ( return { action: "testResults", testResults: groupTestResults( - variables, + // variables, testInputs, testOutputs, testExpectedOutputs @@ -52,69 +52,6 @@ export const getTestResultsPayload = ( }; }; -// export const getTestResultsPayload = (variables: Question["variables"] | undefined): ExtractMessage => { -// // --------------------- -// // Extract overall status -// // --------------------- -// const statusText = -// document -// .querySelector('[data-e2e-locator="console-result"]') -// ?.textContent?.trim() ?? "Unknown Status"; - -// // --------------------- -// // Helper: extract text blocks per label -// // --------------------- -// const extractBlocks = (label: string) => { -// const labels = Array.from( -// document.querySelectorAll(".flex.flex-col .text-xs.font-medium") -// ).filter((el) => el.textContent?.trim() === label); - -// return labels.map((labelEl) => { -// // `.cm-content` inside the same parent hierarchy -// const cmContent = -// labelEl.parentElement?.parentElement?.querySelectorAll(".cm-content"); -// if (!cmContent) return ""; - -// // Combine all lines inside cm-content -// return Array.from(cmContent) -// .map((div) => div.textContent?.trim()) -// .filter(Boolean) -// .join("\n"); -// }); -// }; - -// const inputs = extractBlocks("Input"); -// const outputs = extractBlocks("Output"); -// const expecteds = extractBlocks("Expected"); - -// // --------------------- -// // Combine into testResults array -// // --------------------- -// const testResults = []; -// const maxCases = Math.max(inputs.length, outputs.length, expecteds.length); - -// for (let i = 0; i < maxCases; i++) { -// testResults.push({ -// testResult: [ -// { -// input: inputs[i] ?? "", -// output: outputs[i] ?? "", -// expected: expecteds[i] ?? "", -// }, -// ], -// }); -// } - -// // --------------------- -// // Return payload -// // --------------------- -// return { -// action: "testResults", -// testResults, -// url: getNormalizedUrl(window.location.href), -// }; -// }; - export const getCodePayload = async ( changes: Partial ): Promise> => { diff --git a/extension/src/utils/string.ts b/extension/src/utils/string.ts index ee9c200f..75e263c4 100644 --- a/extension/src/utils/string.ts +++ b/extension/src/utils/string.ts @@ -7,7 +7,7 @@ export const groupTestCases = ( variables: Question["variables"] | undefined, tests: string[] ): TestCase[] => { - if (variables == undefined || tests.length % variables.count !== 0) { + if (variables == undefined) { console.error( "Variables are undefined or tests do not match up", variables, @@ -29,34 +29,60 @@ export const groupTestCases = ( }; export const groupTestResults = ( - variables: Question["variables"] | undefined, + // variables: Question["variables"] | undefined, testInputs: string[], testOutputs: string[], testExpectedOutputs: string[] ): TestResult[] => { - console.log("testResults", testInputs); - if (variables == undefined || testInputs.length % variables.count !== 0) { - console.error( - "Variables are undefined or tests do not match up", - variables, - testInputs - ); + const varCount = testInputs.length / testOutputs.length; + + if (testInputs.length % varCount !== 0) { + console.error("Test inputs length is not a multiple of variable count", { + testInputsLength: testInputs.length, + varCount, + }); return []; } - const chunks = testInputs.length / variables.count; - const groups = Array.from({ length: chunks }, (_, idx) => - testInputs.slice(idx * variables.count, (idx + 1) * variables.count) - ); - return groups.map((group) => ({ - testResult: group.map((assignment, idx) => ({ - variable: variables.names[idx], - value: assignment, - input: assignment, - output: assignment, // Placeholder until we parse properly - expected: assignment, // Placeholder until we parse properly - })), - })); + const numCases = testInputs.length / varCount; + + // If outputs/expected lengths don't match numCases, warn but proceed using available values + if ( + testOutputs.length !== numCases || + testExpectedOutputs.length !== numCases + ) { + console.warn( + "Mismatch between detected number of cases and outputs/expected lengths", + { + numCases, + testOutputsLength: testOutputs.length, + testExpectedOutputsLength: testExpectedOutputs.length, + } + ); + } + + const results: TestResult[] = []; + for (let i = 0; i < numCases; i++) { + const inputObj: Record = {}; + const start = i * varCount; + for (let v = 0; v < varCount; v++) { + // const name = variables.names[v]; + const name = `var${v}`; + inputObj[name] = testInputs[start + v]; + } + + results.push({ + testResult: [ + { + input: inputObj, + output: testOutputs[i] ?? "", + expected: testExpectedOutputs[i] ?? "", + }, + ], + }); + } + + return results; }; export const safeJsonParse = (content: string): object => { From c716de0398e8f037a5c3dfcc0b0127b7c54f4a46 Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Tue, 25 Nov 2025 23:59:37 -0500 Subject: [PATCH 05/14] able to sync input, output, expected output, commit to save prog --- .../src/components/panel/editor/EditorPanel.tsx | 7 +++++++ .../components/panel/editor/tab/TestResultTab.tsx | 15 +++++++++++---- .../src/services/controllers/MessageDispatcher.ts | 9 ++++----- extension/src/types/index.ts | 1 + extension/src/utils/messages.ts | 1 + extension/src/utils/string.ts | 2 ++ 6 files changed, 26 insertions(+), 9 deletions(-) diff --git a/extension/src/components/panel/editor/EditorPanel.tsx b/extension/src/components/panel/editor/EditorPanel.tsx index 3e74e31d..4b5fae80 100644 --- a/extension/src/components/panel/editor/EditorPanel.tsx +++ b/extension/src/components/panel/editor/EditorPanel.tsx @@ -40,6 +40,13 @@ const EditorPanel = () => { const activeTest = selectedPeer?.questions[url]?.tests.find( (test) => test.selected ); + + console.log("activeTest", activeTest); + + // const activeTestResult = selectedPeer?.questions[url]?.testResults.find( + // (testResult) => testResult.selected + // ); + const emptyRoom = Object.keys(peers).length === 0; const upperTabConfigs = React.useMemo(() => { diff --git a/extension/src/components/panel/editor/tab/TestResultTab.tsx b/extension/src/components/panel/editor/tab/TestResultTab.tsx index a5b7a3b4..c97cfe74 100644 --- a/extension/src/components/panel/editor/tab/TestResultTab.tsx +++ b/extension/src/components/panel/editor/tab/TestResultTab.tsx @@ -21,7 +21,7 @@ export const TestResultTab: React.FC = ({
- {(activePeer?.questions[self?.url ?? ""]?.tests ?? []).map( + {(activePeer?.questions[self?.url ?? ""]?.testResults ?? []).map( (test, idx) => (
selectTestResult(idx)}> {test.selected ? ( @@ -48,9 +48,16 @@ export const TestResultTab: React.FC = ({ Input
-
- {String(assignment.input ?? "-")} -
+ {Object.keys(assignment.input ?? {}).map( + (variable: string) => ( +
+ {variable} = {assignment.input[variable]} +
+ ) + )}
{/* Output */} diff --git a/extension/src/services/controllers/MessageDispatcher.ts b/extension/src/services/controllers/MessageDispatcher.ts index c1b29b2e..56da5a18 100644 --- a/extension/src/services/controllers/MessageDispatcher.ts +++ b/extension/src/services/controllers/MessageDispatcher.ts @@ -503,10 +503,9 @@ export class MessageDispatcher { } private getTestResultPayload() { - return getTestResultsPayload( - this.roomStore - .getState() - .actions.room.getVariables(getNormalizedUrl(window.location.href)) - ); + return getTestResultsPayload(); + // this.roomStore + // .getState() + // .actions.room.getVariables(getNormalizedUrl(window.location.href)) } } diff --git a/extension/src/types/index.ts b/extension/src/types/index.ts index e4efee17..0e6c64df 100644 --- a/extension/src/types/index.ts +++ b/extension/src/types/index.ts @@ -16,6 +16,7 @@ interface Assignment { } interface ResultAssignment { + // caseResult: boolean; input: Record; output: string; expected: string; diff --git a/extension/src/utils/messages.ts b/extension/src/utils/messages.ts index a10c63bd..9fa4a9bb 100644 --- a/extension/src/utils/messages.ts +++ b/extension/src/utils/messages.ts @@ -44,6 +44,7 @@ export const getTestResultsPayload = ( action: "testResults", testResults: groupTestResults( // variables, + // caseResults, testInputs, testOutputs, testExpectedOutputs diff --git a/extension/src/utils/string.ts b/extension/src/utils/string.ts index 75e263c4..e76503a4 100644 --- a/extension/src/utils/string.ts +++ b/extension/src/utils/string.ts @@ -30,6 +30,7 @@ export const groupTestCases = ( export const groupTestResults = ( // variables: Question["variables"] | undefined, + // caseResults: boolean[], testInputs: string[], testOutputs: string[], testExpectedOutputs: string[] @@ -74,6 +75,7 @@ export const groupTestResults = ( results.push({ testResult: [ { + // caseResult: caseResults[i] ?? false, input: inputObj, output: testOutputs[i] ?? "", expected: testExpectedOutputs[i] ?? "", From de777e944d5b5674333bd2508590b1b6cd14513a Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Wed, 26 Nov 2025 11:34:13 -0500 Subject: [PATCH 06/14] fix unstable detecting run test button --- .../components/panel/editor/EditorPanel.tsx | 6 -- .../services/controllers/MessageDispatcher.ts | 68 ++++++------------- extension/src/types/index.ts | 1 - extension/src/utils/messages.ts | 8 +-- extension/src/utils/string.ts | 1 - 5 files changed, 21 insertions(+), 63 deletions(-) diff --git a/extension/src/components/panel/editor/EditorPanel.tsx b/extension/src/components/panel/editor/EditorPanel.tsx index 4b5fae80..c66851f1 100644 --- a/extension/src/components/panel/editor/EditorPanel.tsx +++ b/extension/src/components/panel/editor/EditorPanel.tsx @@ -41,12 +41,6 @@ const EditorPanel = () => { (test) => test.selected ); - console.log("activeTest", activeTest); - - // const activeTestResult = selectedPeer?.questions[url]?.testResults.find( - // (testResult) => testResult.selected - // ); - const emptyRoom = Object.keys(peers).length === 0; const upperTabConfigs = React.useMemo(() => { diff --git a/extension/src/services/controllers/MessageDispatcher.ts b/extension/src/services/controllers/MessageDispatcher.ts index 56da5a18..eb2e0dc1 100644 --- a/extension/src/services/controllers/MessageDispatcher.ts +++ b/extension/src/services/controllers/MessageDispatcher.ts @@ -153,57 +153,18 @@ export class MessageDispatcher { return () => observer.disconnect(); } - // private subscribeToRunTest() { - // const observer = new MutationObserver(async () => { - // console.log("Detected run test mutation"); - // const testResult = await this.getTestResultPayload(); - // this.roomStore.getState().actions.self.update({ - // questions: { - // [testResult.url]: { - // testResults: testResult.testResults, - // }, - // }, - // }); - // console.log("Emitting test result -- message dispatcher", testResult); - // this.emitter.emit("rtc.send.message", { - // message: testResult, - // }); - // }); - // waitForElement(DOM.LEETCODE_RUN_TEST_RESULT) - // .then((editor) => { - // console.log("Observing test result editor -- change happened yet 2?", editor); - // observer.observe(editor, { - // attributes: true, - // childList: true, - // subtree: true, - // characterData: true, - // }); - // }) - // .catch(() => - // console.error( - // "Unable to find test result", - // DOM.LEETCODE_RUN_TEST_RESULT - // ) - // ); - // return () => observer.disconnect(); - // } - private subscribeToRunTest(): () => void { let cleanup = () => {}; - - // Attach click handler to the run button. On click, wait for the - // console-result element to appear/change, then scrape and emit. waitForElement('[data-e2e-locator="console-run-button"]') .then((runButton) => { + console.log("Found run button", runButton); const clickHandler = async () => { try { - // Wait for the result container to exist in the DOM + console.log("Run button clicked, waiting for results..."); const resultEl = await waitForElement(DOM.LEETCODE_RUN_TEST_RESULT); - - // Wait for the next meaningful mutation inside the result container. + console.log("Found result element"); await new Promise((resolve, reject) => { const observer = new MutationObserver(() => { - // If the container now has text or children, assume results are present. const hasContent = (resultEl.textContent ?? "").trim().length > 0 || resultEl.children.length > 0; @@ -250,8 +211,18 @@ export class MessageDispatcher { } }; - runButton.addEventListener("click", clickHandler); - cleanup = () => runButton.removeEventListener("click", clickHandler); + const delegatedHandler = (e: MouseEvent) => { + const el = e.target as Element | null; + if (el?.closest('[data-e2e-locator="console-run-button"]')) { + clickHandler(); + } + }; + + document.addEventListener("click", delegatedHandler); + + cleanup = () => { + document.removeEventListener("click", delegatedHandler); + }; }) .catch(() => console.error( @@ -503,9 +474,10 @@ export class MessageDispatcher { } private getTestResultPayload() { - return getTestResultsPayload(); - // this.roomStore - // .getState() - // .actions.room.getVariables(getNormalizedUrl(window.location.href)) + return getTestResultsPayload( + this.roomStore + .getState() + .actions.room.getVariables(getNormalizedUrl(window.location.href)) + ); } } diff --git a/extension/src/types/index.ts b/extension/src/types/index.ts index 0e6c64df..e4efee17 100644 --- a/extension/src/types/index.ts +++ b/extension/src/types/index.ts @@ -16,7 +16,6 @@ interface Assignment { } interface ResultAssignment { - // caseResult: boolean; input: Record; output: string; expected: string; diff --git a/extension/src/utils/messages.ts b/extension/src/utils/messages.ts index 9fa4a9bb..4b656d6d 100644 --- a/extension/src/utils/messages.ts +++ b/extension/src/utils/messages.ts @@ -42,13 +42,7 @@ export const getTestResultsPayload = ( return { action: "testResults", - testResults: groupTestResults( - // variables, - // caseResults, - testInputs, - testOutputs, - testExpectedOutputs - ), + testResults: groupTestResults(testInputs, testOutputs, testExpectedOutputs), url: getNormalizedUrl(window.location.href), }; }; diff --git a/extension/src/utils/string.ts b/extension/src/utils/string.ts index e76503a4..145b8a2d 100644 --- a/extension/src/utils/string.ts +++ b/extension/src/utils/string.ts @@ -75,7 +75,6 @@ export const groupTestResults = ( results.push({ testResult: [ { - // caseResult: caseResults[i] ?? false, input: inputObj, output: testOutputs[i] ?? "", expected: testExpectedOutputs[i] ?? "", From c57025734f8916d3075820b74c073739e0055f18 Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Wed, 26 Nov 2025 16:29:57 -0500 Subject: [PATCH 07/14] complete? --- .../components/panel/editor/EditorPanel.tsx | 15 ++++ .../panel/editor/tab/TestResultTab.tsx | 77 +++++++++++++------ extension/src/store/roomStore.ts | 4 +- extension/src/utils/messages.ts | 28 ++++--- extension/src/utils/string.ts | 36 ++++----- 5 files changed, 101 insertions(+), 59 deletions(-) diff --git a/extension/src/components/panel/editor/EditorPanel.tsx b/extension/src/components/panel/editor/EditorPanel.tsx index c66851f1..a3ab172a 100644 --- a/extension/src/components/panel/editor/EditorPanel.tsx +++ b/extension/src/components/panel/editor/EditorPanel.tsx @@ -49,6 +49,20 @@ const EditorPanel = () => { const activeTestResult = selectedPeer?.questions[url]?.testResults.find( (testResult) => testResult.selected ); + let generalResult = true; + const allTestResult = selectedPeer?.questions[url]?.testResults; + for (const result of allTestResult || []) { + console.log( + "comparison", + result.testResult[0].output, + result.testResult[0].expected + ); + if (result.testResult[0].output !== result.testResult[0].expected) { + generalResult = false; + break; + } + } + return [ { value: "code", @@ -77,6 +91,7 @@ const EditorPanel = () => { activePeer={selectedPeer} activeTestResult={activeTestResult} selectTestResult={selectTestResult} + generalResult={generalResult} /> ), }, diff --git a/extension/src/components/panel/editor/tab/TestResultTab.tsx b/extension/src/components/panel/editor/tab/TestResultTab.tsx index c97cfe74..4825c007 100644 --- a/extension/src/components/panel/editor/tab/TestResultTab.tsx +++ b/extension/src/components/panel/editor/tab/TestResultTab.tsx @@ -7,34 +7,63 @@ interface TestResultTabProps { activePeer: Identifiable | undefined; activeTestResult: SelectableTestResult | undefined; selectTestResult: (index: number) => void; + generalResult: boolean; } export const TestResultTab: React.FC = ({ activePeer, activeTestResult, selectTestResult, + generalResult, }) => { console.log("activeTestResult", activeTestResult); const { self } = useRoomData(); return (
-
+
+
+ {generalResult ? ( + + Accepted + + ) : ( + + Wrong Answer + + )} +
{(activePeer?.questions[self?.url ?? ""]?.testResults ?? []).map( - (test, idx) => ( -
selectTestResult(idx)}> - {test.selected ? ( - - ) : ( - - )} -
- ) + (test, idx) => { + const passed = (test.testResult ?? []).every( + (r: any) => r.output === r.expected + ); + const selected = !!test.selected; + return ( +
selectTestResult(idx)}> + {selected ? ( + passed ? ( + + ) : ( + + ) + ) : passed ? ( + + ) : ( + + )} +
+ ); + } )}
@@ -47,18 +76,18 @@ export const TestResultTab: React.FC = ({
Input
-
- {Object.keys(assignment.input ?? {}).map( - (variable: string) => ( -
+ {Object.keys(assignment.input ?? {}).map( + (variable: string) => ( +
+
{variable} = {assignment.input[variable]}
- ) - )} -
+
+ ) + )} {/* Output */}
diff --git a/extension/src/store/roomStore.ts b/extension/src/store/roomStore.ts index a908cbfc..42006ca4 100644 --- a/extension/src/store/roomStore.ts +++ b/extension/src/store/roomStore.ts @@ -238,13 +238,13 @@ const createRoomStore = (background: BackgroundProxy, appStore: AppStore) => { const setSelfProgressForCurrentUrl = async (question: Question) => { const code = await background.getCode({}); const { tests } = getTestsPayload(question.variables); - // const { testResults } = getTestResultsPayload(question.variables); + const { testResults } = getTestResultsPayload(question.variables); useRoom.getState().actions.self.update({ questions: { [question.url]: { code, tests, - // testResults, + testResults, }, }, }); diff --git a/extension/src/utils/messages.ts b/extension/src/utils/messages.ts index 4b656d6d..f29f0f5f 100644 --- a/extension/src/utils/messages.ts +++ b/extension/src/utils/messages.ts @@ -26,15 +26,18 @@ export const getTestResultsPayload = ( console.log("testResults", testResults); - const testInputs = [...(testResults[0]?.children ?? [])].map( - (line) => (line as HTMLElement).innerText - ); - const testOutputs = [...(testResults[1]?.children ?? [])].map( - (line) => (line as HTMLElement).innerText - ); - const testExpectedOutputs = [...(testResults[2]?.children ?? [])].map( - (line) => (line as HTMLElement).innerText - ); + const countScrapedResult = testResults.length; + + //testResults[0] is the test cases (not test results) most of the time but not always + const testInputs = [ + ...(testResults[countScrapedResult - 3]?.children ?? []), + ].map((line) => (line as HTMLElement).innerText); + const testOutputs = [ + ...(testResults[countScrapedResult - 2]?.children ?? []), + ].map((line) => (line as HTMLElement).innerText); + const testExpectedOutputs = [ + ...(testResults[countScrapedResult - 1]?.children ?? []), + ].map((line) => (line as HTMLElement).innerText); console.log("testInputs", testInputs); console.log("testOutputs", testOutputs); @@ -42,7 +45,12 @@ export const getTestResultsPayload = ( return { action: "testResults", - testResults: groupTestResults(testInputs, testOutputs, testExpectedOutputs), + testResults: groupTestResults( + variables, + testInputs, + testOutputs, + testExpectedOutputs + ), url: getNormalizedUrl(window.location.href), }; }; diff --git a/extension/src/utils/string.ts b/extension/src/utils/string.ts index 145b8a2d..7231b3c2 100644 --- a/extension/src/utils/string.ts +++ b/extension/src/utils/string.ts @@ -29,37 +29,28 @@ export const groupTestCases = ( }; export const groupTestResults = ( - // variables: Question["variables"] | undefined, - // caseResults: boolean[], + variables: Question["variables"] | undefined, testInputs: string[], testOutputs: string[], testExpectedOutputs: string[] ): TestResult[] => { - const varCount = testInputs.length / testOutputs.length; - - if (testInputs.length % varCount !== 0) { - console.error("Test inputs length is not a multiple of variable count", { - testInputsLength: testInputs.length, - varCount, - }); - return []; - } + const numCases = testOutputs.length; + const varCount = testInputs.length / numCases; - const numCases = testInputs.length / varCount; - - // If outputs/expected lengths don't match numCases, warn but proceed using available values if ( + variables == undefined || + testInputs.length % varCount !== 0 || testOutputs.length !== numCases || testExpectedOutputs.length !== numCases ) { - console.warn( - "Mismatch between detected number of cases and outputs/expected lengths", - { - numCases, - testOutputsLength: testOutputs.length, - testExpectedOutputsLength: testExpectedOutputs.length, - } + console.error( + "Variables are undefined or tests do not match up", + variables, + testInputs, + testOutputs, + testExpectedOutputs ); + return []; } const results: TestResult[] = []; @@ -67,8 +58,7 @@ export const groupTestResults = ( const inputObj: Record = {}; const start = i * varCount; for (let v = 0; v < varCount; v++) { - // const name = variables.names[v]; - const name = `var${v}`; + const name = variables.names[v]; inputObj[name] = testInputs[start + v]; } From a12a0f12dc7bb2ff9987808ddf792cb4a855e8e1 Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Wed, 26 Nov 2025 16:47:29 -0500 Subject: [PATCH 08/14] clean up --- .../src/components/panel/editor/EditorPanel.tsx | 8 ++------ extension/src/hooks/toasts/index.ts | 10 ---------- extension/src/types/peers.ts | 14 ++------------ 3 files changed, 4 insertions(+), 28 deletions(-) diff --git a/extension/src/components/panel/editor/EditorPanel.tsx b/extension/src/components/panel/editor/EditorPanel.tsx index a3ab172a..d8e72c53 100644 --- a/extension/src/components/panel/editor/EditorPanel.tsx +++ b/extension/src/components/panel/editor/EditorPanel.tsx @@ -40,23 +40,19 @@ const EditorPanel = () => { const activeTest = selectedPeer?.questions[url]?.tests.find( (test) => test.selected ); - const emptyRoom = Object.keys(peers).length === 0; const upperTabConfigs = React.useMemo(() => { const extension = getLanguageExtension(selectedPeer?.questions[url]?.code?.language) ?? ""; + const activeTestResult = selectedPeer?.questions[url]?.testResults.find( (testResult) => testResult.selected ); + let generalResult = true; const allTestResult = selectedPeer?.questions[url]?.testResults; for (const result of allTestResult || []) { - console.log( - "comparison", - result.testResult[0].output, - result.testResult[0].expected - ); if (result.testResult[0].output !== result.testResult[0].expected) { generalResult = false; break; diff --git a/extension/src/hooks/toasts/index.ts b/extension/src/hooks/toasts/index.ts index 728ad9c3..b63759a8 100644 --- a/extension/src/hooks/toasts/index.ts +++ b/extension/src/hooks/toasts/index.ts @@ -39,16 +39,6 @@ export const useToast = () => { } const { event, user } = message; switch (event) { - case EventType.RUN_TEST_SUCCESS: { - toast.info(`${user} passed all customizable test cases`); - break; - } - - case EventType.RUN_TEST_FAILURE: { - toast.info(`${user} failed some customizable test cases`); - break; - } - case EventType.SUBMIT_SUCCESS: { toast.info(`${user} passed all test cases`); break; diff --git a/extension/src/types/peers.ts b/extension/src/types/peers.ts index 1d6cb115..14e3c78f 100644 --- a/extension/src/types/peers.ts +++ b/extension/src/types/peers.ts @@ -48,8 +48,6 @@ interface SendProgressMessage extends PeerGenericMessage { } export enum EventType { - RUN_TEST_SUCCESS, - RUN_TEST_FAILURE, SUBMIT_SUCCESS, SUBMIT_FAILURE, ADD_QUESTION, @@ -61,10 +59,6 @@ interface PeerGenericEventMessage extends PeerGenericMessage { user: Id; } -interface PeerEventRunTestMesage extends PeerGenericEventMessage { - event: EventType.RUN_TEST_SUCCESS | EventType.RUN_TEST_FAILURE; -} - interface PeerEventSubmissionMesage extends PeerGenericEventMessage { event: EventType.SUBMIT_SUCCESS | EventType.SUBMIT_FAILURE; } @@ -74,10 +68,7 @@ interface PeerEventAddQuestionMessage extends PeerGenericEventMessage { question: string; } -type PeerEventMessage = - | PeerEventRunTestMesage - | PeerEventSubmissionMesage - | PeerEventAddQuestionMessage; +type PeerEventMessage = PeerEventSubmissionMesage | PeerEventAddQuestionMessage; export type PeerMessage = | PeerCodeMessage @@ -85,8 +76,7 @@ export type PeerMessage = | PeerTestResultMessage | PeerEventMessage | RequestProgressMessage - | SendProgressMessage - | PeerEventRunTestMesage; + | SendProgressMessage; interface PeerQuestionProgress { code?: CodeWithChanges; From 50664b68d4f54ab4fd19616ec88774691988537a Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Wed, 26 Nov 2025 17:16:47 -0500 Subject: [PATCH 09/14] random fix UI and clean up --- .../panel/editor/tab/TestResultTab.tsx | 30 +++++++++++-------- .../services/controllers/MessageDispatcher.ts | 1 + extension/src/utils/string.ts | 2 +- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/extension/src/components/panel/editor/tab/TestResultTab.tsx b/extension/src/components/panel/editor/tab/TestResultTab.tsx index 4825c007..4a832e93 100644 --- a/extension/src/components/panel/editor/tab/TestResultTab.tsx +++ b/extension/src/components/panel/editor/tab/TestResultTab.tsx @@ -23,15 +23,19 @@ export const TestResultTab: React.FC = ({
- {generalResult ? ( - - Accepted - - ) : ( - - Wrong Answer - - )} + {activeTestResult ? ( + <> + {generalResult ? ( + + Accepted + + ) : ( + + Wrong Answer + + )} + + ) : null}
{(activePeer?.questions[self?.url ?? ""]?.testResults ?? []).map( @@ -44,20 +48,20 @@ export const TestResultTab: React.FC = ({
selectTestResult(idx)}> {selected ? ( passed ? ( - ) : ( - ) ) : passed ? ( - ) : ( - )} diff --git a/extension/src/services/controllers/MessageDispatcher.ts b/extension/src/services/controllers/MessageDispatcher.ts index eb2e0dc1..97ebc2af 100644 --- a/extension/src/services/controllers/MessageDispatcher.ts +++ b/extension/src/services/controllers/MessageDispatcher.ts @@ -235,6 +235,7 @@ export class MessageDispatcher { } private subscribeToSubmission() { + // todo(nickbar01234): On teardown, we need to revert the changes const sendSuccessSubmission = () => { if (this.appStore.getState().auth.status === AppStatus.AUTHENTICATED) { const url = getNormalizedUrl(window.location.href); diff --git a/extension/src/utils/string.ts b/extension/src/utils/string.ts index 7231b3c2..a1c9f213 100644 --- a/extension/src/utils/string.ts +++ b/extension/src/utils/string.ts @@ -7,7 +7,7 @@ export const groupTestCases = ( variables: Question["variables"] | undefined, tests: string[] ): TestCase[] => { - if (variables == undefined) { + if (variables == undefined || tests.length % variables.count !== 0) { console.error( "Variables are undefined or tests do not match up", variables, From 5a31c91975696afc4355627456af9e63802a92da Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Wed, 26 Nov 2025 17:21:50 -0500 Subject: [PATCH 10/14] tiny UI fix --- .../panel/editor/tab/TestResultTab.tsx | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/extension/src/components/panel/editor/tab/TestResultTab.tsx b/extension/src/components/panel/editor/tab/TestResultTab.tsx index 4a832e93..182bed57 100644 --- a/extension/src/components/panel/editor/tab/TestResultTab.tsx +++ b/extension/src/components/panel/editor/tab/TestResultTab.tsx @@ -26,13 +26,9 @@ export const TestResultTab: React.FC = ({ {activeTestResult ? ( <> {generalResult ? ( - - Accepted - + Accepted ) : ( - - Wrong Answer - + Wrong Answer )} ) : null} @@ -48,20 +44,20 @@ export const TestResultTab: React.FC = ({
selectTestResult(idx)}> {selected ? ( passed ? ( - ) : ( - ) ) : passed ? ( - ) : ( - )} From fa40312907d2572bcdb62f125a649c0bd88f09d0 Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Wed, 26 Nov 2025 17:29:24 -0500 Subject: [PATCH 11/14] clean up debug log --- extension/src/components/panel/editor/tab/TestResultTab.tsx | 1 - extension/src/services/controllers/MessageDispatcher.ts | 5 +---- extension/src/utils/messages.ts | 6 ------ 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/extension/src/components/panel/editor/tab/TestResultTab.tsx b/extension/src/components/panel/editor/tab/TestResultTab.tsx index 182bed57..f5383713 100644 --- a/extension/src/components/panel/editor/tab/TestResultTab.tsx +++ b/extension/src/components/panel/editor/tab/TestResultTab.tsx @@ -16,7 +16,6 @@ export const TestResultTab: React.FC = ({ selectTestResult, generalResult, }) => { - console.log("activeTestResult", activeTestResult); const { self } = useRoomData(); return ( diff --git a/extension/src/services/controllers/MessageDispatcher.ts b/extension/src/services/controllers/MessageDispatcher.ts index 97ebc2af..1061e57d 100644 --- a/extension/src/services/controllers/MessageDispatcher.ts +++ b/extension/src/services/controllers/MessageDispatcher.ts @@ -156,13 +156,10 @@ export class MessageDispatcher { private subscribeToRunTest(): () => void { let cleanup = () => {}; waitForElement('[data-e2e-locator="console-run-button"]') - .then((runButton) => { - console.log("Found run button", runButton); + .then(() => { const clickHandler = async () => { try { - console.log("Run button clicked, waiting for results..."); const resultEl = await waitForElement(DOM.LEETCODE_RUN_TEST_RESULT); - console.log("Found result element"); await new Promise((resolve, reject) => { const observer = new MutationObserver(() => { const hasContent = diff --git a/extension/src/utils/messages.ts b/extension/src/utils/messages.ts index f29f0f5f..88253315 100644 --- a/extension/src/utils/messages.ts +++ b/extension/src/utils/messages.ts @@ -24,8 +24,6 @@ export const getTestResultsPayload = ( document.querySelectorAll(DOM.LEETCODE_TEST_ID) ); - console.log("testResults", testResults); - const countScrapedResult = testResults.length; //testResults[0] is the test cases (not test results) most of the time but not always @@ -39,10 +37,6 @@ export const getTestResultsPayload = ( ...(testResults[countScrapedResult - 1]?.children ?? []), ].map((line) => (line as HTMLElement).innerText); - console.log("testInputs", testInputs); - console.log("testOutputs", testOutputs); - console.log("testExpectedOutputs", testExpectedOutputs); - return { action: "testResults", testResults: groupTestResults( From 3ae4f608d717dc8ffb4b507580b5a61ed70d6d57 Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Thu, 27 Nov 2025 11:18:19 -0500 Subject: [PATCH 12/14] clean up abundant code --- extension/src/components/navigator/menu/UserDropDownMenu.tsx | 3 --- extension/src/types/db.ts | 1 - 2 files changed, 4 deletions(-) diff --git a/extension/src/components/navigator/menu/UserDropDownMenu.tsx b/extension/src/components/navigator/menu/UserDropDownMenu.tsx index 05700462..5a111843 100644 --- a/extension/src/components/navigator/menu/UserDropDownMenu.tsx +++ b/extension/src/components/navigator/menu/UserDropDownMenu.tsx @@ -27,9 +27,6 @@ const STATUS_ICON_MAP: Record = { [QuestionProgressStatus.IN_PROGRESS]: ( ), - [QuestionProgressStatus.RUN_TEST]: ( - - ), [QuestionProgressStatus.COMPLETED]: ( ), diff --git a/extension/src/types/db.ts b/extension/src/types/db.ts index 0abbc84d..dc42ff7f 100644 --- a/extension/src/types/db.ts +++ b/extension/src/types/db.ts @@ -37,7 +37,6 @@ type NegotiationMessage = export enum QuestionProgressStatus { NOT_STARTED = "not-started", IN_PROGRESS = "in-progress", - RUN_TEST = "run-test", COMPLETED = "completed", } From 215ea8ff5afc6d2d86575d5125cda589d8475761 Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Thu, 27 Nov 2025 11:31:58 -0500 Subject: [PATCH 13/14] clean up remove unused code --- extension/src/services/controllers/MessageDispatcher.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/src/services/controllers/MessageDispatcher.ts b/extension/src/services/controllers/MessageDispatcher.ts index 1061e57d..527afa12 100644 --- a/extension/src/services/controllers/MessageDispatcher.ts +++ b/extension/src/services/controllers/MessageDispatcher.ts @@ -331,7 +331,7 @@ export class MessageDispatcher { questions: { [url]: { testResults, - status: QuestionProgressStatus.RUN_TEST, + status: QuestionProgressStatus.IN_PROGRESS, }, }, }); From ffaed7efd2589feac1837118a890b27348ba8663 Mon Sep 17 00:00:00 2001 From: PhuongLe Date: Sat, 29 Nov 2025 14:27:37 -0500 Subject: [PATCH 14/14] tiny clean up --- .../src/components/panel/editor/EditorPanel.tsx | 12 ++++-------- .../components/panel/editor/tab/TestResultTab.tsx | 6 +++--- extension/src/store/roomStore.ts | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/extension/src/components/panel/editor/EditorPanel.tsx b/extension/src/components/panel/editor/EditorPanel.tsx index d8e72c53..90220bd3 100644 --- a/extension/src/components/panel/editor/EditorPanel.tsx +++ b/extension/src/components/panel/editor/EditorPanel.tsx @@ -50,14 +50,10 @@ const EditorPanel = () => { (testResult) => testResult.selected ); - let generalResult = true; - const allTestResult = selectedPeer?.questions[url]?.testResults; - for (const result of allTestResult || []) { - if (result.testResult[0].output !== result.testResult[0].expected) { - generalResult = false; - break; - } - } + const allTestResult = selectedPeer?.questions[url]?.testResults ?? []; + const generalResult = allTestResult.every( + (r) => r.testResult[0].output === r.testResult[0].expected + ); return [ { diff --git a/extension/src/components/panel/editor/tab/TestResultTab.tsx b/extension/src/components/panel/editor/tab/TestResultTab.tsx index f5383713..b625d7d5 100644 --- a/extension/src/components/panel/editor/tab/TestResultTab.tsx +++ b/extension/src/components/panel/editor/tab/TestResultTab.tsx @@ -21,13 +21,13 @@ export const TestResultTab: React.FC = ({
-
+
{activeTestResult ? ( <> {generalResult ? ( - Accepted + Accepted ) : ( - Wrong Answer + Wrong Answer )} ) : null} diff --git a/extension/src/store/roomStore.ts b/extension/src/store/roomStore.ts index 42006ca4..a740ee69 100644 --- a/extension/src/store/roomStore.ts +++ b/extension/src/store/roomStore.ts @@ -208,7 +208,7 @@ const createRoomStore = (background: BackgroundProxy, appStore: AppStore) => { previousSelectedTest >= testResults.length ? testResults.length - 1 : Math.max(previousSelectedTest, 0); - if (testResults[selectedTestIndex] != undefined) { + if (testResults[selectedTestIndex]) { testResults[selectedTestIndex].selected = true; } questionProgressOrDefault.testResults = testResults;