npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@apparts/backend-test

v4.0.1

Published

A framework for database-incorborating backend-testing

Downloads

66

Readme

#+TITLE: @apparts/backend-test #+DATE: [2021-02-11 Thu] #+AUTHOR: Philipp Uhl

This library supports testing @apparts-based backends that use Postgresql databases provide express based APIs.

  • Usage
  1. Add to your =package.json= in the =scripts= section: #+BEGIN_SRC js "testOne": "jest", "test": "jest --watch --detectOpenHandles", "testCoverage": "jest --coverage" #+END_SRC

  2. Create a =jest.config.js= file in the root directory of your project. #+BEGIN_SRC js const jestConfig = require("@apparts/backend-test").getJestConfig();

    module.exports = { ...jestConfig, // additional config }; #+END_SRC

  3. Create a =config/db-test-config.json= or =config/db-test-config.js= or export the values as an environment variable with the name =DB_TEST_CONFIG= with this content (as JSON, for the js file you'd need to export the object): #+BEGIN_EXAMPLE { "use": "postgresql", "postgresql": { "host": "localhost", "port": 5432, "user": "postgres", "pw": "", "db": "", "maxPoolSize": 1, "connectionTimeoutMillis": 10000, "idleTimeoutMillis": 10000, "bigIntAsNumber": true } } #+END_EXAMPLE

  4. Create tests. To use this library, start the tests with this on top: #+BEGIN_SRC js const { app, url, error, getPool } = require("@apparts/backend-test")({ testName: "", // apiContainer: myEndpoint, ...require("./tests/config.js")
    }); #+END_SRC

  5. Create a =tests/config.js= for storing test information that is valid for more than one test: #+BEGIN_SRC js const fs = require("fs"); module.exports = { schemas: ["schema-file-name-0001.sql" /, .../] .map(name => fs.readFileSync(name).toString()), apiVersion: 1, }; #+END_SRC

  6. Run tests with #+BEGIN_SRC sh npm run test

    for coverage report:

    npm run testCoverage

    without watching file changes:

    npm run testOne #+END_SRC

** Parameters

=require("@apparts/backend-test")= returns a function with the following parameters:

  • =testName : string= :: (Required) The name of this particular test (needs to be unique). Used to create a database for this test to run in
  • =apiVersion : int= :: (Required) The API version of a versioned API, that is being tested
  • =apiContainer: object= :: The container for the functions you want [[https://github.com/phuhl/apparts-types][@apparts/types]] =checkApiTypes= to test against. If this parameter is not supplied, =checkType= and =allChecked= will throw an error.
  • =schemas : [string]= :: Database schemas, to be run first to create all tables
  • =databasePreparations : [async function : string]= :: A list of functions (that can be async) that return strings, containing sql code that should be run to setup the database
  • =testApp : express app= :: If supplied, this app will be used as the express app, the tests will be performed on. Otherwise a default test app will be used.

** Returns

=require("@apparts/backend-test")= returns a function wich returns an object with the following key/value pairs:

  • =checkType : (any, string) => boolean= :: A wrapper around the =checkType= function from the [[https://github.com/phuhl/apparts-types][@apparts/types]] package. The first parameter of =checkType= is already set (with value from =apiContainer= parameter) for convenience.
  • =allChecked : (string) => boolean= :: A wrapper around the ==allChecked= function from the [[https://github.com/phuhl/apparts-types][@apparts/types]] package. The first parameter of =allChecked= is already set (with value from =apiContainer= parameter) for convenience.
  • =app : = :: A express app. It lacks routes, these have to be added manually. A minimal middleware is already applied to this app (injection of database, body parser).
  • =url : (string) => string= :: A helper that turns a string to a versioned version of this string, by prepending =/v//= to the string. =apiVersion= is the value of the parameter =apiVersion=. This allows to change the api-version of all calls with one variable.
  • =error : (string, ?string) => object= :: A helper that creates an object of the form of the body, produced by the =HttpError= from the package [[https://github.com/phuhl/apparts-error][@apparts/error]]. Can be used with the supertest =toMatchObject= matcher.
  • =runDBQuery : async (async () => any) => any= :: A function that expects a function as parameter. This function receives a [[https://github.com/phuhl/apparts-db][@apparts/db]] =DBS= object as parameter. It's return value will be awaited and returned by =runDBQuery=.
  • =getPool : () => = :: Returns a [[https://github.com/phuhl/apparts-db][@apparts/db]] =DBS= object.

** Minimal example

  • =jest.config.js=: #+BEGIN_SRC js const jestConfig = require("@apparts/backend-test").getJestConfig();

    module.exports = { ...jestConfig, // additional config }; #+END_SRC

  • =config/db-test-config.json= as described above

  • Tests with #+BEGIN_SRC js const { app, url } = require("@apparts/backend-test")({ testName: "", apiVersion: 1 });

    test("My test", async () => { // requesting GET "/v/1/test" const response = await request(app).get(url("test")); expect(response.status).toBe(200); }); #+END_SRC

** Full-ish example

#+BEGIN_SRC js const { app, url, checkType, allChecked, error, getPool, } = require("@apparts/backend-test")({ testName: "", apiContainer: require("./myEndpoint"),

// Returns everything that is the same for all endpoints of this
// APIs version: apiVersion, schemas
...require("./tests/config.json") ,

// Insert values for the tests to use.
databasePreparations: [
  // Common setup queries can be stored in a file
  require("./tests/insertUsers.sql.js"),
  // Simple insertations
  () => 'INSERT INTO "myTable" (myCollumn) VALUES (1), (2)';
  // More complicated calculated values
  async () => {
    const hash = await require("bcryptjs").hash("password123", 10);
    return `INSERT INTO "passwords" (password) VALUES (${hash})`;
  };
],

});

const request = require("supertest");

describe("GET test", () => { // Using a variable for the function name makes it easy to copy this // test for another endpoint and not forgot to change the function // name in some places. const functionName = "myEndpoint"; test("Check return code", async () => { // Requesting GET "/v/1/test", using the url function. This makes // it easy to copy this file, edit the tests to reflect api changes // and thus reuse it for the next api version. const response = await request(app).get(url("test")); expect(response.status).toBe(200);

  // Checking against the database
  // const dbs = getPool();
  // await dbs.raw("SELECT ...");
  // expect(...);

  // Throws if not correct, so no expect is needed
  checkType(response, functionName);
});

test("Check error", async () => {
  const response = await request(app).get(url("test/error"));
  expect(response.status).toBe(400);
  expect(response.body).toMatchObject(error("This endpoint fails", "Reason: \"error\""));
  checkType(response, functionName);
});

test(("All possible responses tested") => {
  // Throws if not all checked, so no expect is needed
  allChecked(functionName);
});

}); #+END_SRC