Skip to content

Commit 6644621

Browse files
committed
テストページをterminal/page.tsxに統一
1 parent d3394ff commit 6644621

File tree

2 files changed

+163
-90
lines changed

2 files changed

+163
-90
lines changed

app/terminal/page.tsx

Lines changed: 163 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,124 @@
22
import { Heading } from "@/[docs_id]/markdown";
33
import "mocha/mocha.js";
44
import "mocha/mocha.css";
5-
import { useEffect, useRef, useState } from "react";
5+
import { Fragment, useEffect, useRef, useState } from "react";
66
import { useWandbox } from "./wandbox/runtime";
77
import { RuntimeContext, RuntimeLang } from "./runtime";
88
import { useEmbedContext } from "./embedContext";
99
import { defineTests } from "./tests";
1010
import { usePyodide } from "./worker/pyodide";
1111
import { useRuby } from "./worker/ruby";
1212
import { useJSEval } from "./worker/jsEval";
13+
import { ReplTerminal } from "./repl";
14+
import { EditorComponent, getAceLang } from "./editor";
15+
import { ExecFile } from "./exec";
1316

1417
export default function RuntimeTestPage() {
18+
return (
19+
<div className="p-4 mx-auto w-full max-w-200">
20+
<Heading level={1}>Runtime Test Page</Heading>
21+
22+
<Heading level={2}>REPLとコード実行のサンプル</Heading>
23+
{/* name of each tab group should be unique */}
24+
<div className="tabs tabs-border">
25+
{Object.entries(sampleConfig).map(([lang, config]) => (
26+
<Fragment key={lang}>
27+
<input
28+
type="radio"
29+
name="runtime-sample-tabs"
30+
className="tab"
31+
aria-label={lang}
32+
/>
33+
<div className="tab-content border-base-300 bg-base-100 p-4">
34+
<RuntimeSample lang={lang as RuntimeLang} config={config} />
35+
</div>
36+
</Fragment>
37+
))}
38+
</div>
39+
40+
<Heading level={2}>自動テスト</Heading>
41+
<MochaTest />
42+
</div>
43+
);
44+
}
45+
46+
interface SampleConfig {
47+
repl: boolean;
48+
replInitContent?: string; // ReplOutput[] ではない。stringのパースはruntimeが行う
49+
editor: Record<string, string> | false;
50+
exec: string[] | false;
51+
}
52+
const sampleConfig: Record<RuntimeLang, SampleConfig> = {
53+
python: {
54+
repl: true,
55+
replInitContent: '>>> print("Hello, World!")\nHello, World!',
56+
editor: {
57+
"main.py": 'print("Hello, World!")',
58+
},
59+
exec: ["main.py"],
60+
},
61+
ruby: {
62+
repl: true,
63+
replInitContent: '>> puts "Hello, World!"\nHello, World!',
64+
editor: {
65+
"main.rb": 'puts "Hello, World!"',
66+
},
67+
exec: ["main.rb"],
68+
},
69+
javascript: {
70+
repl: true,
71+
replInitContent: '> console.log("Hello, World!");\nHello, World!',
72+
editor: false,
73+
exec: false,
74+
},
75+
cpp: {
76+
repl: false,
77+
editor: {
78+
"main.cpp": `#include <iostream>
79+
#include "sub.h"
80+
81+
int main() {
82+
std::cout << "Hello, World!" << std::endl;
83+
}`,
84+
"sub.h": ``,
85+
"sub.cpp": ``,
86+
},
87+
exec: ["main.cpp", "sub.cpp"],
88+
},
89+
};
90+
function RuntimeSample({
91+
lang,
92+
config,
93+
}: {
94+
lang: RuntimeLang;
95+
config: SampleConfig;
96+
}) {
97+
return (
98+
<div className="flex flex-col gap-4">
99+
{config.repl && (
100+
<ReplTerminal
101+
terminalId="1"
102+
language={lang}
103+
initContent={config.replInitContent}
104+
/>
105+
)}
106+
{config.editor &&
107+
Object.entries(config.editor).map(([filename, initContent]) => (
108+
<EditorComponent
109+
key={filename}
110+
language={getAceLang(lang)}
111+
filename={filename}
112+
initContent={initContent}
113+
/>
114+
))}
115+
{config.exec && (
116+
<ExecFile filenames={config.exec} language={lang} content="" />
117+
)}
118+
</div>
119+
);
120+
}
121+
122+
function MochaTest() {
15123
const pyodide = usePyodide();
16124
const ruby = useRuby();
17125
const javascript = useJSEval();
@@ -23,16 +131,15 @@ export default function RuntimeTestPage() {
23131
javascript: javascript,
24132
cpp: wandboxCpp,
25133
};
26-
const { files, writeFile } = useEmbedContext();
27-
const filesRef = useRef<Record<string, string>>({});
28-
filesRef.current = files;
29-
const [mochaState, setMochaState] = useState<"idle" | "running" | "finished">(
30-
"idle"
31-
);
134+
32135
const [searchParams, setSearchParams] = useState<string>("");
33136
useEffect(() => {
34137
setSearchParams(window.location.search);
35138
}, []);
139+
const [mochaState, setMochaState] = useState<"idle" | "running" | "finished">(
140+
"idle"
141+
);
142+
const { writeFile } = useEmbedContext();
36143

37144
const runTest = () => {
38145
setMochaState("running");
@@ -50,59 +157,56 @@ export default function RuntimeTestPage() {
50157
};
51158

52159
return (
53-
<div className="p-4 mx-auto w-full max-w-200">
54-
<Heading level={1}>Runtime Test Page</Heading>
55-
<div className="border-1 border-transparent translate-x-0">
56-
{/* margin collapseさせない & fixedの対象をviewportではなくこのdivにする */}
57-
{mochaState === "idle" ? (
58-
<button className="btn btn-primary mt-4" onClick={runTest}>
59-
テストを実行
60-
</button>
61-
) : mochaState === "running" ? (
62-
<div className="alert mt-16 sm:mt-4 w-80">
63-
<svg
64-
xmlns="http://www.w3.org/2000/svg"
65-
className="animate-spin h-5 w-5 mr-3 border-2 border-solid border-current border-t-transparent rounded-full"
66-
fill="none"
67-
viewBox="0 0 24 24"
68-
></svg>
69-
テストを実行中です...
70-
</div>
71-
) : (
72-
<div className="alert mt-16 sm:mt-4 w-80">
73-
<svg
74-
xmlns="http://www.w3.org/2000/svg"
75-
fill="none"
76-
viewBox="0 0 24 24"
77-
className="stroke-info h-6 w-6 shrink-0"
78-
>
79-
<path
80-
strokeLinecap="round"
81-
strokeLinejoin="round"
82-
strokeWidth="2"
83-
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
84-
></path>
85-
</svg>
86-
テストが完了しました
87-
</div>
160+
<div className="border-1 border-transparent translate-x-0">
161+
{/* margin collapseさせない & fixedの対象をviewportではなくこのdivにする */}
162+
{mochaState === "idle" ? (
163+
<button className="btn btn-primary mt-4" onClick={runTest}>
164+
テストを実行
165+
</button>
166+
) : mochaState === "running" ? (
167+
<div className="alert mt-16 sm:mt-4 w-80">
168+
<svg
169+
xmlns="http://www.w3.org/2000/svg"
170+
className="animate-spin h-5 w-5 mr-3 border-2 border-solid border-current border-t-transparent rounded-full"
171+
fill="none"
172+
viewBox="0 0 24 24"
173+
></svg>
174+
テストを実行中です...
175+
</div>
176+
) : (
177+
<div className="alert mt-16 sm:mt-4 w-80">
178+
<svg
179+
xmlns="http://www.w3.org/2000/svg"
180+
fill="none"
181+
viewBox="0 0 24 24"
182+
className="stroke-info h-6 w-6 shrink-0"
183+
>
184+
<path
185+
strokeLinecap="round"
186+
strokeLinejoin="round"
187+
strokeWidth="2"
188+
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
189+
></path>
190+
</svg>
191+
テストが完了しました
192+
</div>
193+
)}
194+
<p className="mt-8">
195+
{new URLSearchParams(searchParams).has("grep") && (
196+
<>
197+
一部のテストだけを実行します:
198+
<code className="ml-2 font-mono">
199+
{new URLSearchParams(searchParams).get("grep")}
200+
</code>
201+
{/* eslint-disable-next-line @next/next/no-html-link-for-pages */}
202+
<a className="ml-4 link link-info" href="/terminal">
203+
{/* aタグでページをリロードしないと動作しない。 */}
204+
フィルタを解除
205+
</a>
206+
</>
88207
)}
89-
<p className="mt-8">
90-
{new URLSearchParams(searchParams).has("grep") && (
91-
<>
92-
一部のテストだけを実行します:
93-
<code className="ml-2 font-mono">
94-
{new URLSearchParams(searchParams).get("grep")}
95-
</code>
96-
{/* eslint-disable-next-line @next/next/no-html-link-for-pages */}
97-
<a className="ml-4 link link-info" href="/terminal">
98-
{/* aタグでページをリロードしないと動作しない。 */}
99-
フィルタを解除
100-
</a>
101-
</>
102-
)}
103-
</p>
104-
<div className="m-0!" id="mocha" />
105-
</div>
208+
</p>
209+
<div className="m-0!" id="mocha" />
106210
</div>
107211
);
108212
}

app/terminal/wandbox/page.tsx

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)