Skip to content

Commit 51c5fb4

Browse files
committed
Update docs and lint configuration for quotes
1 parent 78d3781 commit 51c5fb4

File tree

15 files changed

+149
-29
lines changed

15 files changed

+149
-29
lines changed

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,32 @@ If you are a developer looking to do things like create a new bundle or work wit
2121
| `js-slang` | https://github.com/source-academy/js-slang |
2222
| Frontend | https://github.com/source-academy/frontend |
2323

24+
## Repository Structure
25+
26+
```txt
27+
.
28+
├── .github
29+
│ ├── actions // Custom Github Actions
30+
│ └── workflow // CI/CD Workflow files
31+
├── build // Output for compiled assets
32+
├── devserver // Development Server
33+
├── docs // Documentation Server
34+
├── lib
35+
│ ├── __test_mocks__ // Mock bundles and tabs used for testing
36+
│ ├── buildtools // Command line tools for bundles and tabs
37+
│ ├── lintplugin // ESLint Plugin
38+
│ ├── markdown-tree // Markdown-It plugin for generating directory trees
39+
│ ├── modules-lib // Common library for utilities used by bundles and tabs
40+
│ └── repotools // Repository wide tooling
41+
├── src // Code for bundles, tabs and java-slang
42+
│ ├── bundles
43+
│ ├── tabs
44+
│ └── java
45+
├── vitest.config.js // Root Vitest Config
46+
├── eslint.config.js // ESLint Config
47+
└── yarn.config.cjs // Yarn Constraints file
48+
```
49+
2450
## Building the documentation server
2551

2652
1. Run the command: `yarn workspaces focus @sourceacademy/modules-docserver`

docs/src/modules/1-getting-started/3-git.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ When making changes to the code in this repository, you should abide by some goo
1818
> When you add a dependency to your bundle/tab, remember to run your installation command to ensure that the lockfile gets updated, and then
1919
> commit the changes to the lockfile.
2020
21+
> [!WARNING] package-lock.json
22+
> If you accidentally run installation commands with `npm` instead (i.e `npm i`), a different type of lockfile will get generated. This file should be
23+
> deleted if present and should not be added to the repository.
24+
2125
## Creating your own branch
2226

2327
The `master` branch of the repository is protected. This means that you cannot push commits directly to it, nor can pull requests be merged
@@ -45,3 +49,12 @@ Once your code has been reviewed, the pull request will be merged.
4549
## Opening Issues
4650

4751
If you have a bug report or feature request, open an issue with the appropriate label(s) [here](https://github.com/source-academy/modules/issues)
52+
53+
## `.gitignore` Files
54+
55+
You should include files that are produced from compilation into your own `.gitignore` file and avoid committing them to the repository. By default,
56+
the `dist` folders are ignored for all bundles and tabs, but if you need to add other files you can create a custom `.gitignore` in your bundle/tab's
57+
directory.
58+
59+
> [!TIP]
60+
> If you want to remove a file that been committed in the past you can use `git rm`

docs/src/modules/1-getting-started/4-cheat.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,16 @@ All commands have a `-h` or `--help` option that can be used to get more informa
2323
</tr>
2424
<tr>
2525
<td><code>yarn workspaces focus @sourceacademy/bundle-curve</code></td>
26-
<td>Installs the dependencies required for the `curve` bundle <strong>only</strong> </td>
26+
<td>Installs the dependencies required for the <code>curve</code> bundle <strong>only</strong> </td>
2727
</tr>
2828
<tr>
29-
<td><code>yarn add &lt;package&gt;</code>*</td>
29+
<td><code>yarn add &lt;package&gt;</code></td>
3030
<td>
3131
Adds a package to the current bundle or tab <br />
3232
</td>
3333
</tr>
3434
<tr>
35-
<td><code>yarn add -D &lt;package&gt;</code>*</td>
35+
<td><code>yarn add -D &lt;package&gt;</code></td>
3636
<td>
3737
Adds a package to the current bundle or tab that will only be used during runtime <br />
3838
</td>
@@ -156,10 +156,10 @@ In general, global scripts for this repository follow the same format.
156156
- `:modules` will be run for all bundle and tab code
157157

158158
> [!WARNING] On Focused Installs
159-
> If you used a focus install, the dependencies for the other bundles and tabs will not be available. In fact, the root
159+
> If you used a focused install, the dependencies for the other bundles and tabs will not be available. The root
160160
> repository's package may not have been installed either.
161161
>
162-
> This means that many of the `:all` and `:modules` commands will not work. You should use the bundle or tab specific
162+
> Without the root package being installed, many of the `:all` and `:modules` commands may not work. You can still use the bundle or tab specific
163163
> commands instead.
164164
165165
<table>

docs/src/modules/2-bundle/4-conventions/2-abstractions.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ Functionally, `Sound` behaves like a primitive type: as far as a cadet using the
3535
## Breaking Abstractions with `display` and `stringify`
3636

3737
`js-slang` provides a built-in function for converting any value into a string: `stringify()`. `display()` behaves like the typical `console.log` and prints the string representation
38-
as returned by `stringify` to the REPL. Under the hood, `stringify` uses the default Javascript `toString` functionality to convert primitive types to their string representations. This does
39-
mean that for "primitives" that are actually objects, `js-slang`'s default implementation will end up exposing implementation details.
38+
as returned by `stringify` to the REPL. Under the hood, `stringify` uses the default Javascript `toString` functionality to convert Javascript types to their string representations. This does
39+
mean that for Source primitives that are actually Javascript objects, `js-slang`'s default implementation will end up exposing implementation details.
4040

4141
Taking an example from the `curve` bundle, `RenderFunction`s are considered a type of primitive. Without any further changes, calling `display` on a `RenderFunction` produces the following
4242
output:
@@ -116,6 +116,13 @@ export class Point implements ReplResult {
116116
`Point` is a class that directly implements the `ReplResult` interface. If it didn't implement this interface, then calling `display(make_point(20, 20))`
117117
would result in the infamous `[object Object]` being printed.
118118

119+
The type doesn't have to be a class, it can also be a Typescript [interface](https://www.typescriptlang.org/docs/handbook/2/objects.html):
120+
```ts
121+
interface Thing extends ReplResult {
122+
// ...implementation details
123+
}
124+
```
125+
119126
The benefit of implementing the interface this way in Typescript is that it enables type-checking to ensure that the interface is properly implemented.
120127

121128
### Implementing `ReplResult` indirectly
@@ -251,4 +258,4 @@ const options = create_text_options('blue', 20);
251258
change_text_options(options);
252259
```
253260

254-
The idea is that the abstraction of the `TextOptions` type is never broken and that the cadet never interacts with the object directly.
261+
The idea is that the abstraction of the `TextOptions` type is never broken and that the cadet never interacts with the object's component parts directly.

docs/src/modules/2-bundle/4-conventions/3-errors.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Then, the error can be thrown with the correct function name. Otherwise, cadets
5353
that is visible to them. Many other functions might rely on `throwIfNotRune`. If they were all called in the same program, it doesn't tell the cadet which function the error was thrown from
5454
(was it `show`? or `anaglyph`? or something else?)
5555

56-
## Type Checking
56+
## Source Type Checking
5757

5858
Though bundles are written in Typescript, Source (except for the Typed Variant) does not support anything beyond rudimentary type checking. This means that it can determine that an expression
5959
like `1 - "string"` is badly typed, but it can't type check more complex programs like the one below, especially when bundle functions are involved:

docs/src/modules/4-testing/2-devserver/2-devserver.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,5 @@ to compiled mode by following the steps below:
4444

4545
2. Switch to compiled mode
4646
![](./step2.png)
47+
48+
If need be, you can use the the textbox to customize which server to load modules from.

docs/src/modules/4-testing/4-unit.md

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ The default testing configuration for tabs has browser mode disabled. This is so
211211
212212
### Setting up Browser Mode
213213
214-
Should you wish to enable browser mode, create a custom `vitest` configuration file for your tab with the `browswer.enabled` option set to `true`:
214+
Should you wish to enable browser mode, create a custom `vitest` configuration file for your tab with the `browser.enabled` option set to `true`:
215215
216216
```js {9}
217217
// @ts-check
@@ -228,11 +228,23 @@ export default defineProject({
228228
});
229229
```
230230
231-
Now, the tests for your tab will be run in browser mode.
231+
You will also need to add (to your dev dependencies) other packages:
232+
- `@vitest/browser`
233+
- `vitest-browser-react`
234+
- `playwright`
235+
236+
In the case of `playwright`, you might also have to run `playwright install chromium`.
237+
238+
If your system doesn't have the necessary dependencies for `playwright`'s install, you will have to run `playwright install chromium --with-deps` instead.
239+
240+
Now, the tests for your tab can be run in browser mode.
232241
233242
> [!INFO] Default Browser Instance
234243
> By default, one `chromium` browser instance will be provided. This should be sufficient, but you can always
235244
> add more instances if necessary.
245+
>
246+
> Then, you will also have to specify this instance when running the `playwright` installation command above.
247+
236248
237249
### Writing Interactive Tests
238250
@@ -350,3 +362,55 @@ test('An animation', async () => {
350362
await expect.element(finishScreen).toBeVisible();
351363
});
352364
```
365+
366+
### Element Locators
367+
368+
In the above examples, you might have noticed that we can actually grab elements that are within the DOM and do things with them (like performing
369+
assertions or clicking).
370+
371+
`vitest` provides several ways to "locate" an element helpfully called [locators](https://vitest.dev/guide/browser/locators.html).
372+
373+
While writing tabs, if we believe that a component will need to be interacted with during unit testing, we can use attributes like `title` to make it
374+
easier to refer to these elements:
375+
376+
```tsx
377+
export function Foo() {
378+
return <p title="important" />;
379+
}
380+
381+
// Can then be referred to:
382+
test('test0', () => {
383+
const screen = render(<Foo />);
384+
const p = screen.getByTitle('important');
385+
await expect.element(p).toBeVisible();
386+
});
387+
```
388+
389+
### Simulating User Input
390+
391+
You can simulate user input by using the `userEvent` utility from `@vitest/browser`:
392+
```tsx
393+
export function Foo() {
394+
const [text, setText] = useState('');
395+
return <div>
396+
<input
397+
onChange={e => setText(e.target.value)}
398+
value={text}
399+
/>
400+
<p>You said: {text}</p>
401+
</div>;
402+
}
403+
404+
// In tests:
405+
import { userEvent } from '@vitest/browser/context';
406+
import { render } from 'vitest-browser-react';
407+
408+
test('Changing text works', () => {
409+
const screen = render(<Foo />);
410+
await userEvent.keyboard('abcd');
411+
const element = screen.getByText('abcd');
412+
await expect.element(element).toBeVisible();
413+
});
414+
```
415+
416+
It can also simulate sustained keypresses, mouse inputs and a whole lot of [other things](https://testing-library.com/docs/user-event/keyboard/).

eslint.config.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,15 @@ export default tseslint.config(
394394
rules: {
395395
'no-empty-pattern': 'off', // vitest requires certain things to be destructured using an object pattern
396396

397-
'@stylistic/quotes': 'off', // Turn this off to avoid conflicting with snapshots
397+
// Change to avoid conflicting with snapshots
398+
'@stylistic/quotes': [
399+
'warn',
400+
'single',
401+
{
402+
avoidEscape: true,
403+
allowTemplateLiterals: 'always'
404+
}
405+
],
398406

399407
'vitest/expect-expect': ['error', {
400408
assertFunctionNames: ['expect*'],

lib/buildtools/src/commands/__tests__/commandUtils.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import type { Severity } from "@sourceacademy/modules-repotools/types";
2-
import { describe, expect, test } from "vitest";
3-
import { processResult } from "../commandUtils.js";
1+
import type { Severity } from '@sourceacademy/modules-repotools/types';
2+
import { describe, expect, test } from 'vitest';
3+
import { processResult } from '../commandUtils.js';
44

55
describe('Testing processResults', () => {
66
const testCases: [any, Severity][] = [

lib/buildtools/src/testing/__tests__/utils.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ describe('Test getTestConfiguration', () => {
270270
mockedReadFile.mockImplementation(p => {
271271
if (p === pathlib.join(libPath, 'package.json')) {
272272
return Promise.resolve(JSON.stringify({
273-
name: "@sourceacademy/a-pacakge"
273+
name: '@sourceacademy/a-pacakge'
274274
}));
275275
}
276276
throw new ENOENT();

0 commit comments

Comments
 (0)