Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ on:
- main

jobs:
meilisearch-version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get-version-step.outputs.meilisearch_version }}
steps:
- uses: actions/checkout@v5
- name: Get required version of meilisearch
id: get-version-step
run: |
MEILISEARCH_VERSION=$(node -p "require('./package.json').meilisearchTargetVersion")
echo "meilisearch_version=$MEILISEARCH_VERSION" >> $GITHUB_OUTPUT
integration_tests:
# Will not run if the event is a PR to bump-meilisearch-v* (so a pre-release PR)
# Will not run if the event is a PR to pre-release-beta/*
Expand All @@ -25,9 +36,10 @@ jobs:
!startsWith(github.base_ref, 'prototype-beta/') &&
!startsWith(github.head_ref, 'pre-release-beta/')
runs-on: ubuntu-latest
needs: meilisearch-version
services:
meilisearch:
image: getmeili/meilisearch:latest
image: getmeili/meilisearch:v${{ needs.meilisearch-version.outputs.version }}
env:
MEILI_MASTER_KEY: 'masterKey'
MEILI_NO_ANALYTICS: 'true'
Expand Down
17 changes: 12 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,24 @@ First of all, thank you for contributing to Meilisearch! The goal of this docume

To run this project, you will need:

- Node >= v20 and Node <= 22
- Yarn v1.x
- [Node.js v20 or newer](https://nodejs.org/en/download)
- [Docker](https://www.docker.com/products/docker-desktop/)

### Setup

You can set up your local environment natively or using `docker`, check out the [`docker-compose.yml`](/docker-compose.yml).
To enable [corepack](https://github.com/nodejs/corepack) for
[Yarn](https://classic.yarnpkg.com/en/) to work:

Example of running all the checks with docker:
```bash
corepack enable
```

To run Meilisearch for testing:

```bash
docker-compose run --rm package bash -c "yarn install && yarn test && yarn lint"
yarn docker
# or if you wish to run it in the background in detached mode
yarn docker -d
```

To install dependencies:
Expand Down
22 changes: 0 additions & 22 deletions docker-compose.yml

This file was deleted.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "meilisearch",
"version": "0.53.0",
"meilisearchTargetVersion": "1.18.0",
"description": "The Meilisearch JS client for Node.js and the browser.",
"keywords": [
"meilisearch",
Expand Down Expand Up @@ -61,7 +62,8 @@
"lint:fix": "eslint --fix",
"style": "yarn fmt && yarn lint",
"style:fix": "yarn fmt:fix && yarn lint:fix",
"prepare": "husky"
"prepare": "husky",
"docker": "node scripts/docker-meilisearch.js"
},
"files": [
"src",
Expand Down
10 changes: 8 additions & 2 deletions src/meilisearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -473,8 +473,14 @@ export class MeiliSearch {
*
* @returns Promise returning an object with health details
*/
async health(): Promise<Health> {
return await this.httpRequest.get<Health>({ path: "health" });
async health(
// TODO: Need to do this for all other methods: https://github.com/meilisearch/meilisearch-js/issues/1476
extraRequestInit?: ExtraRequestInit,
): Promise<Health> {
return await this.httpRequest.get<Health>({
path: "health",
extraRequestInit,
});
}

/**
Expand Down
7 changes: 3 additions & 4 deletions tests/errors.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { test, describe, beforeEach, vi } from "vitest";
import { test, describe, vi, beforeAll } from "vitest";
import { MeiliSearch, assert } from "./utils/meilisearch-test-utils.js";
import { MeiliSearchRequestError } from "../src/index.js";

const mockedFetch = vi.fn();
globalThis.fetch = mockedFetch;

describe("Test on updates", () => {
beforeEach(() => {
mockedFetch.mockReset();
beforeAll(() => {
globalThis.fetch = mockedFetch;
});

test(`Throw MeilisearchRequestError when thrown error is not MeiliSearchApiError`, async () => {
Expand Down
141 changes: 141 additions & 0 deletions tests/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { spawnSync } from "node:child_process";
import { MeiliSearch } from "../src/meilisearch.js";
import pkg from "../package.json" with { type: "json" };

const POLL_INTERVAL = 250;
const CONTAINER_NAME = "meilisearch";
const TIMEOUT = 15_000;
const TIMEOUT_ID = Symbol();

const ms = new MeiliSearch({
host: "http://127.0.0.1:7700",
apiKey: "masterKey",
});

function removeIfExistsMeilisearchDockerService(): void {
spawnSync(
"docker",

// https://docs.docker.com/reference/cli/docker/container/rm/
["container", "rm", "-f", CONTAINER_NAME],

// TODO: prefix output
{ stdio: "inherit" },
);
}

function startMeilisearchDockerService(meilisearchVersion: string): void {
spawnSync(
"docker",
[
// https://docs.docker.com/reference/cli/docker/container/run
"run",

// https://docs.docker.com/reference/cli/docker/container/run/#rm
"--rm",

// https://docs.docker.com/reference/cli/docker/container/run/#detach
"-d",

// https://docs.docker.com/reference/cli/docker/container/run/#name
"--name",
CONTAINER_NAME,

// https://docs.docker.com/reference/cli/docker/container/run/#publish
"-p",
"7700:7700",

// https://docs.docker.com/reference/cli/docker/container/run/#env
"-e",
"MEILI_MASTER_KEY=masterKey",
"-e",
"MEILI_NO_ANALYTICS=true",

// https://hub.docker.com/r/getmeili/meilisearch
`getmeili/meilisearch:v${meilisearchVersion}`,
],

// TODO: prefix output
{ stdio: "inherit" },
);
}

/** Poll Meilisearch until its reachable. */
async function waitForMeiliSearch(): Promise<void> {
let lastError;

const ac = new AbortController();

const toId = setTimeout(() => void ac.abort(TIMEOUT_ID), TIMEOUT);

for (;;) {
try {
await ms.health({ signal: ac.signal });

clearTimeout(toId);

break;
} catch (error) {
if (Object.is((error as Error).cause, TIMEOUT_ID)) {
throw new Error(
`connection unsuccessful to meilisearch after ${TIMEOUT}ms`,
{ cause: lastError },
);
}

lastError = error;
}

await new Promise<void>((resolve) => setTimeout(resolve, POLL_INTERVAL));
}
}

/**
* In case there is a connection, return Meilisearch version, and
* `null`otherwise.
*/
async function checkConnectionAndVersion(): Promise<string | null> {
try {
const { pkgVersion } = await ms.getVersion();
return pkgVersion;
} catch {
return null;
}
}

// TODO: could use docker image save/load and https://github.com/actions/cache?tab=readme-ov-file
// instead of github workflows services

/**
* If there is no connection to Meilisearch, create a docker service of it, and
* wait for connection.
*
* {@link https://vitest.dev/config/#globalsetup}
*/
export default async function () {
const { meilisearchTargetVersion } = pkg;

const meilisearchVersion = await checkConnectionAndVersion();
if (meilisearchVersion !== null) {
if (meilisearchVersion !== meilisearchTargetVersion) {
throw new Error(
"Meilisearch is reachable but it is the wrong version " +
`(expected ${meilisearchTargetVersion}, got ${meilisearchVersion})`,
);
}

return;
}

try {
removeIfExistsMeilisearchDockerService();
startMeilisearchDockerService(meilisearchTargetVersion);
await waitForMeiliSearch();

return removeIfExistsMeilisearchDockerService;
} catch (error) {
removeIfExistsMeilisearchDockerService();

throw error;
}
}
1 change: 1 addition & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default defineConfig(({ mode }) => {
: undefined,
},
test: {
globalSetup: "tests/setup.ts",
include: ["tests/**/*.test.ts"],
exclude: ["tests/env/**"],
fileParallelism: false,
Expand Down