Skip to content
Merged
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
21 changes: 21 additions & 0 deletions packages/docs/docs-dev/testing/integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Integration tests

Integration tests exercise multiple packages working together and often rely on
sample projects from the [`test-files`](../../../test-files) directory. They are
written with [Vitest](https://vitest.dev) and follow the `*.test.ts` naming
convention alongside the sources.

Typical scenarios include:

- Remote procedure calls via the runtime `Communicator`.
- Round‑tripping DAWproject data through import and export utilities using
fixtures like `all-devices.od` and `automation.dawproject`.

Run all integration suites with:

```bash
npm test
```

This command executes every package's test script via Turbo, ensuring that
features continue to work together across the monorepo.
4 changes: 2 additions & 2 deletions packages/docs/docs-dev/testing/test-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ cover common scenarios and are used across packages for development and regressi

| File | Description |
| --- | --- |
| `all-devices.od` | OpenDAW project exercising a wide range of built-in devices. |
| `all-devices.od` | OpenDAW project exercising a wide range of built-in devices; used by exporter integration tests. |
| `eq.dawproject` | DAWproject fixture containing EQ settings. |
| `note-regions.dawproject` | Demonstrates note regions across tracks. |
| `automation.dawproject` | Includes parameter automation curves. |
| `automation.dawproject` | Includes parameter automation curves for automation tests. |
| `audio-regions.dawproject` | Contains audio regions with linked media. |
| `bitwig.example.xml` | Minimal Bitwig project used for parser tests. |

Expand Down
1 change: 1 addition & 0 deletions packages/docs/docs-user/examples/test-projects.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ projects in the [`test-files`](../../../../test-files) directory:
- **bitwig.example.xml** – a tiny Bitwig project useful for import experiments.

These projects are read‑only fixtures; copy them before making changes.
Developers can reuse them in [integration tests](../../docs-dev/testing/integration.md).
16 changes: 16 additions & 0 deletions packages/lib/midi/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Smoke tests for the MIDI entry module, ensuring exports and global registration.
*/
import { describe, expect, it } from "vitest";
import * as Midi from "./index";

describe("lib-midi index", () => {
it("registers a global symbol", () => {
const key = Symbol.for("@openDAW/lib-midi");
expect((globalThis as any)[key]).toBe(true);
});

it("exposes MidiFileDecoder", () => {
expect(Midi.MidiFileDecoder).toBeTypeOf("function");
});
});
126 changes: 74 additions & 52 deletions packages/studio/core/src/dawproject/DawProjectExporter.test.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,76 @@
import {describe, it} from "vitest"
import {fileURLToPath} from "url"
import * as path from "node:path"
import * as fs from "node:fs"
import {Project} from "../Project"
import {AudioData, SampleLoader, SampleLoaderState, SampleManager} from "@opendaw/studio-adapters"
import {Observer, Option, panic, Subscription, Terminable, UUID} from "@opendaw/lib-std"
import {Xml} from "@opendaw/lib-xml"
import {FileReferenceSchema} from "@opendaw/lib-dawproject"
import {DawProjectExporter} from "./DawProjectExporter"
import {Peaks} from "@opendaw/lib-fusion"

/** Verifies that a project can be exported to DAWproject format. */
/**
* Verifies that a complex OpenDAW project exports to DAWproject format.
*/
import { describe, it } from "vitest";
import { fileURLToPath } from "url";
import * as path from "node:path";
import * as fs from "node:fs";
import { Project } from "../Project";
import {
AudioData,
SampleLoader,
SampleLoaderState,
SampleManager,
} from "@opendaw/studio-adapters";
import {
Observer,
Option,
panic,
Subscription,
Terminable,
UUID,
} from "@opendaw/lib-std";
import { Xml } from "@opendaw/lib-xml";
import { FileReferenceSchema } from "@opendaw/lib-dawproject";
import { DawProjectExporter } from "./DawProjectExporter";
import { Peaks } from "@opendaw/lib-fusion";

describe("DawProjectExport", () => {
it("export", async () => {
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const projectPath = "../../../../../test-files/all-devices.od"
const buffer = fs.readFileSync(path.join(__dirname, projectPath))
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength)
const project = Project.load({
sampleRate: 44100,
sampleManager: new class implements SampleManager {
record(loader: SampleLoader & { uuid: UUID.Format }): void {
throw new Error("Method not implemented.")
}
getOrCreate(format: UUID.Format): SampleLoader {
return new class implements SampleLoader {
data: Option<AudioData> = Option.None
peaks: Option<Peaks> = Option.None
uuid: UUID.Format = format
state: SampleLoaderState = {type: "progress", progress: 0.0}
meta: Option<any> = Option.None
invalidate(): void {throw new Error("Method not implemented.")}
subscribe(_observer: Observer<SampleLoaderState>): Subscription {
return Terminable.Empty
}
}
}
invalidate(_uuid: UUID.Format): void {
return panic("Method not implemented.")
}
}
}, arrayBuffer)
const schema = DawProjectExporter.write(project, {
write: (path: string, buffer: ArrayBufferLike): FileReferenceSchema => {
console.debug(`store ${buffer.byteLength} bytes at ${path}`)
return Xml.element({path, external: false}, FileReferenceSchema)
}
})
// console.dir(schema, {depth: Number.MAX_SAFE_INTEGER})
console.debug(Xml.pretty(Xml.toElement("Project", schema)))
})
})
it("export", async () => {
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const projectPath = "../../../../../test-files/all-devices.od";
const buffer = fs.readFileSync(path.join(__dirname, projectPath));
const arrayBuffer = buffer.buffer.slice(
buffer.byteOffset,
buffer.byteOffset + buffer.byteLength,
);
const project = Project.load(
{
sampleRate: 44100,
sampleManager: new (class implements SampleManager {
record(loader: SampleLoader & { uuid: UUID.Format }): void {
throw new Error("Method not implemented.");
}
getOrCreate(format: UUID.Format): SampleLoader {
return new (class implements SampleLoader {
data: Option<AudioData> = Option.None;
peaks: Option<Peaks> = Option.None;
uuid: UUID.Format = format;
state: SampleLoaderState = { type: "progress", progress: 0.0 };
meta: Option<any> = Option.None;
invalidate(): void {
throw new Error("Method not implemented.");
}
subscribe(_observer: Observer<SampleLoaderState>): Subscription {
return Terminable.Empty;
}
})();
}
invalidate(_uuid: UUID.Format): void {
return panic("Method not implemented.");
}
})(),
},
arrayBuffer,
);
const schema = DawProjectExporter.write(project, {
write: (path: string, buffer: ArrayBufferLike): FileReferenceSchema => {
console.debug(`store ${buffer.byteLength} bytes at ${path}`);
return Xml.element({ path, external: false }, FileReferenceSchema);
},
});
// console.dir(schema, {depth: Number.MAX_SAFE_INTEGER})
console.debug(Xml.pretty(Xml.toElement("Project", schema)));
void schema;
});
});
34 changes: 18 additions & 16 deletions packages/studio/core/src/dawproject/DawProjectImport.test.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import {describe, it} from "vitest"
import {fileURLToPath} from "url"
import * as path from "node:path"
import * as fs from "node:fs"
import {DawProject} from "./DawProject"
import {DawProjectImport} from "./DawProjectImport"

/** Basic sanity checks for the DAWproject importer. */
/**
* Basic sanity checks for the DAWproject importer using a sample EQ project.
*/
import { describe, it } from "vitest";
import { fileURLToPath } from "url";
import * as path from "node:path";
import * as fs from "node:fs";
import { DawProject } from "./DawProject";
import { DawProjectImport } from "./DawProjectImport";

describe("DawProjectImport", () => {
it("import", async () => {
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const testFile = "../../../../../test-files/eq.dawproject"
const buffer = fs.readFileSync(path.join(__dirname, testFile))
const {project, resources} = await DawProject.decode(buffer)
const {skeleton} = await DawProjectImport.read(project, resources)
})
})
it("import", async () => {
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const testFile = "../../../../../test-files/eq.dawproject";
const buffer = fs.readFileSync(path.join(__dirname, testFile));
const { project, resources } = await DawProject.decode(buffer);
const { skeleton } = await DawProjectImport.read(project, resources);
void skeleton;
});
});