Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/tests/smoke/create/create.test.ts
12921 views
1
/*
2
* create.test.ts
3
*
4
* Copyright (C) 2020-2022 Posit Software, PBC
5
*
6
*/
7
8
import { execProcess } from "../../../src/core/process.ts";
9
import { join } from "../../../src/deno_ral/path.ts";
10
import { walkSync } from "../../../src/deno_ral/fs.ts";
11
import { CreateResult } from "../../../src/command/create/cmd-types.ts";
12
import { assert } from "testing/asserts";
13
import { quartoDevCmd } from "../../utils.ts";
14
15
const kCreateTypes: Record<string, string[]> = {
16
"project": ["website", "default", "book", "website:blog"],
17
"extension": [
18
"filter",
19
"shortcode",
20
"revealjs-plugin",
21
"journal",
22
"format:html",
23
"format:pdf",
24
"format:docx",
25
"format:revealjs",
26
"engine",
27
],
28
};
29
30
const tempDir = Deno.makeTempDirSync();
31
for (const type of Object.keys(kCreateTypes)) {
32
for (const template of kCreateTypes[type]) {
33
Deno.test(`quarto create ${type} ${template}`, async (t) => {
34
// Configure the item to test
35
const artifactName = template.replaceAll(/:/gm, "");
36
const artifactPath = join(tempDir, artifactName);
37
const createDirective = {
38
type,
39
directive: {
40
directory: artifactPath,
41
template,
42
name: artifactName,
43
},
44
};
45
46
// Create the artifact
47
let result: CreateResult | undefined = undefined;
48
await t.step(`> quarto ${type} ${template}`, async () => {
49
// test quarto cmd render
50
const cmd = [quartoDevCmd(), "create", "--json"];
51
const stdIn = JSON.stringify(createDirective);
52
const process = await execProcess({
53
cmd: cmd[0],
54
args: cmd.slice(1),
55
stdout: "piped",
56
stderr: "piped",
57
}, stdIn);
58
assert(process.success, process.stderr);
59
if (process.stdout) {
60
result = JSON.parse(process.stdout) as CreateResult;
61
}
62
assert(process.success, process.stderr);
63
});
64
65
// Verify all created files are user-writable.
66
// NOTE: In dev environments, resource files are already writable (0o644),
67
// so this test passes even without ensureUserWritable. It guards against
68
// regressions; the unit test in file-permissions.test.ts covers the
69
// read-only → writable transition directly.
70
await t.step({
71
name: `> check writable ${type} ${template}`,
72
ignore: Deno.build.os === "windows",
73
fn: () => {
74
for (const entry of walkSync(artifactPath)) {
75
if (entry.isFile) {
76
const stat = Deno.statSync(entry.path);
77
assert(
78
stat.mode !== null && (stat.mode! & 0o200) !== 0,
79
`File ${entry.path} is not user-writable (mode: ${stat.mode?.toString(8)})`,
80
);
81
}
82
}
83
},
84
});
85
86
// Render the artifact
87
await t.step(`> render ${type} ${template}`, async () => {
88
const path = result!.path;
89
const openfiles = result!.openfiles;
90
assert(
91
openfiles.length > 0,
92
`Artifact ${type} ${template} failed to produce any files to open.`,
93
);
94
95
// Build engine extensions before rendering
96
if (template === "engine") {
97
const buildCmd = [quartoDevCmd(), "call", "build-ts-extension"];
98
const buildProcess = await execProcess({
99
cmd: buildCmd[0],
100
args: buildCmd.slice(1),
101
cwd: path,
102
stdout: "piped",
103
stderr: "piped",
104
});
105
assert(buildProcess.success, buildProcess.stderr);
106
}
107
108
for (const file of openfiles) {
109
if (file.endsWith(".qmd")) {
110
// provide a step name and function
111
const cmd = [quartoDevCmd(), "render", file];
112
const process = await execProcess({
113
cmd: cmd[0],
114
args: cmd.slice(1),
115
cwd: path,
116
stdout: "piped",
117
stderr: "piped",
118
});
119
assert(process.success, process.stderr);
120
}
121
}
122
});
123
124
// Cleanup the artifact dir
125
Deno.removeSync(artifactPath, { recursive: true });
126
});
127
}
128
}
129
130