{"id":11506,"library":"ospec","title":"ospec: Noiseless Testing Framework","description":"ospec is a lightweight and \"noiseless\" JavaScript testing framework, currently at version 4.2.1. It aims for terser and faster test code compared to alternatives like Mocha, Jasmine, or Tape, emphasizing readability through its Subject-Verb-Object assertion structure. The framework includes features for test grouping, asynchronous tests, `before/after` hooks, test exclusivity (`.only`), and spies for mocking functions. Its core design principle is to regulate test-space configuration to promote focus on testing logic and encourage uniform test suites. The project maintains a small footprint, aiming for around 800 lines of code after a planned API surface change, with a current release cadence that reflects ongoing development and refinements.","status":"active","version":"4.2.1","language":"javascript","source_language":"en","source_url":"https://github.com/MithrilJS/ospec","tags":["javascript","testing"],"install":[{"cmd":"npm install ospec","lang":"bash","label":"npm"},{"cmd":"yarn add ospec","lang":"bash","label":"yarn"},{"cmd":"pnpm add ospec","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"ospec exports the main 'o' function as a default export in both CommonJS and ESM. Avoid destructuring 'o' from the require statement.","wrong":"const o = require('ospec').o","symbol":"o","correct":"import o from 'ospec'"},{"note":"For CommonJS environments, 'o' is the direct module.exports. Using ESM import syntax in a CJS context will result in syntax errors.","wrong":"import o from 'ospec'","symbol":"o","correct":"const o = require('ospec')"},{"note":"'o.spec' is a method on the default exported 'o' function, not a named export itself. Import 'o' first, then access 'spec' as a property.","wrong":"import { spec } from 'ospec'","symbol":"o.spec","correct":"import o from 'ospec'; o.spec('group', () => { /* ... */ })"}],"quickstart":{"code":"import o from 'ospec';\n\n// Basic test and assertions\no.spec(\"math operations\", function() {\n    o(\"addition works\", function() {\n        o(1 + 1).equals(2)(\"basic addition assertion\");\n        o(2 + 2).equals(4);\n    });\n\n    o(\"subtraction works\", function() {\n        o(1 - 1).notEquals(2)(\"basic subtraction assertion\");\n    });\n\n    // Nested test groups\n    o.spec(\"arithmetics details\", function() {\n        o(\"multiplication also works\", function() {\n            o(2 * 3).equals(6);\n        });\n    });\n});\n\n// Example with o.spy for function call tracking\nfunction executeCallback(cb, arg) {\n    cb(arg);\n}\n\no.spec(\"executeCallback()\", function() {\n    o(\"calls the provided callback with the argument\", function() {\n        var spy = o.spy();\n        executeCallback(spy, \"test-argument\");\n\n        o(spy.callCount).equals(1)(\"spy should be called once\");\n        o(spy.args[0]).equals(\"test-argument\")(\"first call argument should match\");\n        o(spy.calls[0].args).deepEquals([\"test-argument\"])(\"full call arguments should deep equal\");\n    });\n});\n\n// To run the tests, typically you would run this file via the `ospec` CLI or call o.run()\n// Assuming a simple setup where tests are executed on file load, \n// or for explicit execution, the 'ospec' runner needs to be invoked. \n// For demonstration, we simulate running all defined tests.\n// In a real CLI setup, this explicit `o.run()` might not be needed.\n// However, if running directly in Node, it might be. Let's omit for general quickstart.\n// A typical setup would involve `npx ospec my-tests.js`\n\n// Example of an async test\no.spec(\"async operations\", function() {\n    o(\"handles promises correctly\", function(done) {\n        Promise.resolve(5).then(result => {\n            o(result).equals(5);\n            done(); // Important for async tests to signal completion\n        });\n    });\n});\n","lang":"javascript","description":"Demonstrates basic test definition, grouping, nested groups, assertions, spy usage, and asynchronous testing with ospec."},"warnings":[{"fix":"Review your test suites periodically against the latest documentation and migration guides for updated API usage. Adapt to new patterns to ensure forward compatibility.","message":"The ospec API surface is currently undergoing changes. Both legacy and updated APIs are present to ease transition, but users relying on older patterns should anticipate potential breaking changes in future major releases once legacy code is removed.","severity":"breaking","affected_versions":">=4.x"},{"fix":"For callback-style async tests, ensure the `done` argument is accepted and called upon test completion. For Promise-based tests, return the Promise from the test function.","message":"Asynchronous tests in ospec require calling the `done()` callback or returning a Promise to signal completion. Failing to do so will cause the test to exit prematurely or time out.","severity":"gotcha","affected_versions":">=1.0"},{"fix":"Use either `o(val).equals(expected)('Your assertion description')` or `o(val).equals(expected) `Your assertion description`` for adding descriptions to assertions.","message":"When providing a description for an assertion, ospec uses a function call `o(...).equals(...)('description')` or template literal syntax `o(...).equals(...) `description``. Using a comma `o(...).equals(..., 'description')` is incorrect and will be treated as an additional argument to the assertion method.","severity":"gotcha","affected_versions":">=1.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure you have `const o = require('ospec')` for CommonJS or `import o from 'ospec'` for ESM at the top of your test file.","cause":"The 'o' function was not correctly imported or required, or you might be trying to access a property on an undefined 'o'.","error":"TypeError: o is not a function"},{"fix":"For callback-style async tests, ensure `done()` is called when the async operation completes. For Promise-based tests, ensure the test function returns the Promise. You may also need to increase the timeout for long-running async operations.","cause":"An asynchronous test or hook function did not call the `done()` callback or return a Promise within the default timeout period.","error":"Error: Timeout awaiting async test"},{"fix":"Review the values being asserted and the expected outcomes. Ensure your test logic correctly produces the state you're asserting against. Use `deepEquals` for object comparison instead of `equals`.","cause":"An assertion condition was not met (e.g., `o(1).equals(2)`).","error":"Error: assertion failed"}],"ecosystem":"npm"}