Skip to main content

Creating Tests

Writing and managing tests is just as important as the code itself. So, let's learn about best practices for directory structures for storing tests when developing applications with Geajs, as well as what kinds of tests you should write.

test Directory Structure​

When writing tests for applications built with geajs, what is the best structure for the test directory?
While opinions on this may vary from person to person, here we'll introduce the configuration recommended by the Geastack Community. First, we'll assume that the directory where the tests are stored is named test. This isn't so much because there's a specific reason for it, but rather because the Geastack Community typically uses that name for its test directories. (Both test and tests are common conventions across the JS ecosystem — we simply standardize on test for consistency across packages.)

In the case of a monorepo, the structure is as follows:

.
├── ecosystems
│ └── geajs // There might be even deeper layers like this.
│ ├── abc
│ │ ├── package.json
│ │ ├── src (dir)
│ │ ├── test (dir)
│ │ └── tsconfig.json
│ ├── def
│ │ ├── package.json
│ │ ├── src (dir)
│ │ ├── test (dir)
│ │ └── tsconfig.json
├── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── tsconfig.json
└── vitest.workspace.ts

In the case of a polyrepo, the structure is as follows:

.
├── src (dir)
├── test (dir)
├── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── tsconfig.json
└── vitest.workspace.ts

Now, let's take a look at the contents of the test directory.

In geajs, the basic rule is that each file exports exactly one Store or Component, and nothing else is written in that file. For this reason, placing test components or stores in the file where you write the tests themselves isn't really a good idea. Therefore, you should extract them into a separate file. However, if you try to do this too rigidly, another problem arises: the test directory ends up mixed with test files and files implementing components and stores for testing, making it difficult to manage. Therefore, you should place minimal, disposable Gea component and store implementations in a subdirectory under the test directory. Let's look at the following example:

. // Directories and files not related to testing have been omitted.
└── test (dir)
├── index.test.ts
├── context.browser.test.tsx
└── fixtures/
├── context.browser/
│ ├── child-probe.tsx
│ ├── parent-probe.tsx
│ ├── middle-probe.tsx
│ └── orphan-probe.tsx
└── counter-store.ts

Let's take a look at this directory structure. First, there are two test files: index.test.ts and context.browser.test.tsx. These are located directly under the test/ directory. These two files do not contain any implementations of Store or Component. So, what's inside the fixtures directory? In this example, the fixtures directory contains one file (counter-store.ts) and one folder (context.browser) with four files inside it. What does this indicate?

Within the fixtures directory, organize directories and files according to the following rules:

  • Shared fixtures used by multiple test files within a given test directory should be placed directly under the fixtures directory. counter-store.ts is an example — it's a minimal Store implementation reused across several test files, so it lives at the top level.
  • For fixtures used by only a single test file, use a directory name derived from that test file's name by removing the trailing .test.ts or .test.tsx extension (e.g., abc.test.ts → abc, foo.bar.test.tsx → foo.bar), and place the fixture inside that directory. child-probe.tsx, parent-probe.tsx, middle-probe.tsx, and orphan-probe.tsx are all used exclusively by context.browser.test.tsx, so they all live under fixtures/context.browser/ — none of them belong at the top level of fixtures/, even though they might look similar to shared fixtures at a glance.

Doing this allows you to take advantage of the directory structure, making maintenance easier: whether a fixture is shared or single-use is visible from its path alone, with no need to open the file or check every test that might import it.