Giter VIP home page Giter VIP logo

testing's Introduction

@iobroker/testing

This repo provides utilities for testing of ioBroker adapters and other ioBroker-related modules. It supports:

  • Unit tests using mocks (without a running JS-Controller)
  • Integration tests that test against a running JS-Controller instance.

The unit tests are realized using the following tools that are provided by this module:

  • A mock database which implements the most basic functionality of ioBroker's Objects and States DB by operating on Map objects.
  • A mock Adapter that is connected to the mock database. It implements basic functionality of the real Adapter class, but only operates on the mock database.

Predefined methods for both unit and integration tests are exported.

Usage

Validating package files (package.json, io-package.json, ...)

const path = require("path");
const { tests } = require("@iobroker/testing");

// Run tests
tests.packageFiles(path.join(__dirname, ".."));
//                 ~~~~~~~~~~~~~~~~~~~~~~~~~
// This should be the adapter's root directory

Adapter startup (Integration test)

Run the following snippet in a mocha test file to test the adapter startup process against a real JS-Controller instance:

const path = require("path");
const { tests } = require("@iobroker/testing");

// Run tests
tests.integration(path.join(__dirname, ".."), {
	//            ~~~~~~~~~~~~~~~~~~~~~~~~~
	// This should be the adapter's root directory

	// If the adapter may call process.exit during startup, define here which exit codes are allowed.
	// By default, termination during startup is not allowed.
	allowedExitCodes: [11],

	// To test against a different version of JS-Controller, you can change the version or dist-tag here.
	// Make sure to remove this setting when you're done testing.
	controllerVersion: "latest", // or a specific version like "4.0.1"

	// Define your own tests inside defineAdditionalTests
	defineAdditionalTests({ suite }) {
		// All tests (it, describe) must be grouped in one or more suites. Each suite sets up a fresh environment for the adapter tests.
		// At the beginning of each suite, the databases will be reset and the adapter will be started.
		// The adapter will run until the end of each suite.

		// Since the tests are heavily instrumented, each suite gives access to a so called "harness" to control the tests.
		suite("Test sendTo()", (getHarness) => {
			// For convenience, get the current suite's harness before all tests
			let harness;
			before(() => {
				harness = getHarness();
			});

			it("Should work", () => {
				return new Promise(async (resolve) => {
					// Start the adapter and wait until it has started
					await harness.startAdapterAndWait();

					// Perform the actual test:
					harness.sendTo("adapter.0", "test", "message", (resp) => {
						console.dir(resp);
						resolve();
					});
				});
			});
		});

		// While developing the tests, you can run only a single suite using `suite.only`...
		suite.only("Only this will run", (getHarness) => {
			// ...
		});
		// ...or prevent a suite from running using `suite.skip`:
		suite.skip("This will never run", (getHarness) => {
			// ...
		});
	},
});

Adapter startup (Unit test)

Unit tests for adapter startup were removed and are essentially a no-op now.
If you defined your own tests, they should still work.

const path = require("path");
const { tests } = require("@iobroker/testing");

tests.unit(path.join(__dirname, ".."), {
	//     ~~~~~~~~~~~~~~~~~~~~~~~~~
	// This should be the adapter's root directory

	// Define your own tests inside defineAdditionalTests.
	// If you need predefined objects etc. here, you need to take care of it yourself
	defineAdditionalTests() {
		it("works", () => {
			// see below how these could look like
		});
	},
});

Helper functions for your own tests

Under utils, several functions are exposed to use in your own tests:

const { utils } = require("@iobroker/testing");

Currently, only utils.unit is defined which contains tools for unit tests:

createMocks()

const { database, adapter } = utils.unit.createMocks();
// or (with custom adapter options)
const { database, adapter } = utils.unit.createMocks(adapterOptions);

This method creates a mock database and a mock adapter. See below for a more detailed description

createAsserts()

const asserts = utils.unit.createAsserts(database, adapter);

This methods takes a mock database and adapter and creates a set of asserts for your tests. All IDs may either be a string, which is taken literally, or an array of strings which are concatenated with ".". If an ID is not fully qualified, the adapter namespace is prepended automatically.

  • assertObjectExists(id: string | string[]) asserts that an object with the given ID exists in the database.
  • assertStateExists(id: string | string[]) asserts that a state with the given ID exists in the database.
  • assertStateHasValue(id: string | string[], value: any) asserts that a state has the given value.
  • assertStateIsAcked(id: string | string[], ack: boolean = true) asserts that a state is acked (or not if ack === false).
  • assertStateProperty(id: string | string[], property: string, value: any) asserts that one of the state's properties (e.g. from) has the given value
  • assertObjectCommon(id: string | string[], common: ioBroker.ObjectCommon) asserts that an object's common part includes the given common object.
  • assertObjectNative(id: string | string[], native: object) asserts that an object's native part includes the given native object.

MockDatabase

TODO

MockAdapter

TODO

Example

Here's an example how this can be used in a unit test:

import { tests, utils } from "@iobroker/testing";

// Run tests
tests.unit(path.join(__dirname, ".."), {
	//     ~~~~~~~~~~~~~~~~~~~~~~~~~
	// This should be the adapter's root directory

	// Define your own tests inside defineAdditionalTests
	defineAdditionalTests() {
		// Create mocks and asserts
		const { adapter, database } = utils.unit.createMocks();
		const { assertObjectExists } = utils.unit.createAsserts(
			database,
			adapter,
		);

		describe("my test", () => {
			afterEach(() => {
				// The mocks keep track of all method invocations - reset them after each single test
				adapter.resetMockHistory();
				// We want to start each test with a fresh database
				database.clear();
			});

			it("works", () => {
				// Create an object in the fake db we will use in this test
				const theObject: ioBroker.PartialObject = {
					_id: "whatever",
					type: "state",
					common: {
						role: "whatever",
					},
				};
				mocks.database.publishObject(theObject);

				// Do something that should be tested

				// Assert that the object still exists
				assertObjectExists(theObject._id);
			});
		});
	},
});

testing's People

Contributors

alcalzone avatar apollon77 avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar foxriver76 avatar germanbluefox avatar lgtm-com[bot] avatar mcm1957 avatar mischroe avatar unclesamswiss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

testing's Issues

overwriteAdapterConfig does not override config settings in unit test

Hi,

I try to use overwriteAdapterConfig for my adapter`s unit test. In overwriteAdapterConfig I set some settings:

overwriteAdapterConfig(config) {
		config.devices[0] = {'1':'2'};
		config.devpath = '/dev/ttyUSB0';

	}

But this setting (config.devpath) not exists in config object in adapter`s instance in onReady handler:

onReady() {
		return new Promise((res) => {
			this.serialport = new SerialPort(this.config.devpath)
				// wait for the open event before claiming we are ready
				.on('open', () => res())
				// TODO: add other event handlers
			;
			// @ts-ignore
			if (!this.serialport.isOpen && !this.serialport.opening)
				this.serialport.open();
		}).then(() => {
			// in this template all states changes inside the adapters namespace are subscribed
			this.subscribeStates('*');
			this.log.debug('adapter ' + this.name + 'is ready');
		});
	}

What I do, for use settings config.devpath in my tests?

objects mock no longer necessary

Due to ioBroker/ioBroker.js-controller#359 we want to prevent devs from using adapter.objects and adapter.states thus we should remove providing the functionality of mocking objects https://github.com/ioBroker/testing/blob/master/src/tests/unit/mocks/mockObjects.ts

Furthermore, the two pre-implemented methods https://github.com/ioBroker/testing/blob/master/src/tests/unit/mocks/mockObjects.ts#L22 are now part of the adapter class itself.

Thus, the two methods should be provided in this module and the objects mock should be removed.

Create mock separately for each adapter`s instance

Hi,

I use SerialPort.MockBinding and inject mock into my adapter. MockBinding require call CreatePort method with port path, for example /dev/ttyUSB0. Test library run few instance of adapter (normal and compact mode). In second instance of adapter I catch error 'can't open port. Port is locked'. I need create mock separately per each adapter`s instance. Ho can I do it?

changeAdapterConfig not working as expected

Edit: (AlCalzone)
changeAdapterConfig now works in 2.5.4. It only accepts 2 parameters though:

await harness.changeAdapterConfig('hm-rpc', obj);

Original issue

Hi @AlCalzone,

public async changeAdapterConfig(
is not working as expected, I changed the config via

       describe('Test connection', () => {
            it('Should work', () => {
                return new Promise(async resolve => {
                    const harness = getHarness();
                    // change the adapter config
                    const obj = {
                        native: {
                            homematicAddress: '127.0.0.1',
                            homematicPort: 2010
                        }
                    };
                    await harness.changeAdapterConfig('', '', 'hm-rpc', obj);
                    harness.objects.getObject('system.adapter.hm-rpc.0', (err, obj) => {
                        console.log(JSON.stringify(obj))
....

In the console.log, the config has not been applied. Also I don't get why it's necessary to specify appName and testDir if its not used. Currently I have to change my config by the following code:

                    harness.objects.getObject('system.adapter.hm-rpc.0', (err, obj) => {
                        obj.native.homematicAddress = '127.0.0.1';
                        obj.native.homematicPort = 2010;
                        harness.objects.setObject(obj._id, obj);
...

This works.

Unit test for non-compact mode fails if export is done by checking module and require.main

Using

if (require.main === module) {
    startAdapter();
} else {
    // export for compact mode
    module.exports = startAdapter;
}

as start condition fails with the following error:

Test the adapter (in a mocked environment)
       The adapter starts in normal mode:
     Error: The adapter was not initialized!
      at Object.<anonymous> (node_modules/@iobroker/testing/build/tests/unit/harness/startMockAdapter.js:108:23)
      at Generator.next (<anonymous>)
      at /home/moritz/workspaces/ioBroker.denon/node_modules/@iobroker/testing/build/tests/unit/harness/startMockAdapter.js:28:71
      at new Promise (<anonymous>)
      at __awaiter (node_modules/@iobroker/testing/build/tests/unit/harness/startMockAdapter.js:24:12)
      at Object.startMockAdapter (node_modules/@iobroker/testing/build/tests/unit/harness/startMockAdapter.js:50:12)
      at Context.<anonymous> (node_modules/@iobroker/testing/build/tests/unit/index.js:67:83)
      at Generator.next (<anonymous>)
      at /home/moritz/workspaces/ioBroker.denon/node_modules/@iobroker/testing/build/tests/unit/index.js:10:71
      at new Promise (<anonymous>)
      at __awaiter (node_modules/@iobroker/testing/build/tests/unit/index.js:6:12)
      at Context.<anonymous> (node_modules/@iobroker/testing/build/tests/unit/index.js:63:20)

Object does not exists in mock database after test

Hi,

I want to check my code for correct remove object from iobroker database. I have following preset objects:

predefinedObjects: [
		{
			'_id': 'noolitef.0.testlamp', 
			'type': 'channel',
			// @ts-ignore
			'parent': 'noolitef.0',        
			 'children': [
				'noolitef.0.testlamp.status',
				'noolitef.0.testlamp.channel'
			 ],
			'common': {
				'name':  'testlamp',      
				'role':  'light.switch',         
				'desc':  'fill comment for test purpose'                     
			}
		 },
		 {
			'_id': 'noolitef.0.badlamp', 
			'type': 'channel',
			// @ts-ignore
			'parent': 'noolitef.0',         
			 'children': [
				'noolitef.0.badlamp.status',
				'noolitef.0.baslamp.channel'
			 ],
			'common': {
				'name':  'badlamp',      
				'role':  'light.switch',          
				'desc':  'fill comment for test purpose'                   
			}
		 }
	],
	predefinedStates: {
		'noolitef.0.testlamp.status' : {'val' :false, 'ack':false},
		'noolitef.0.testlamp.channel' : {'val' :1, 'ack' : false}
	}

In main.js I do nothing and then I try to check exits object in database:

const result = database.hasObject('noolitef.0.badlamp');

The 'result' is false. I think that object 'noolitef.0.badlamp' must be exists and 'result' must be 'true'

several test cases after one adapter start

as of today it seems that the test cases with it() need to execute the harness.AdaperStartAndWait.
Having a real integration with a mock server, the whole startup of the adapter is processed with each it().
In my opinion it would be more helpful to have additional the approach to have the harness.AdaperStartAndWait in the before() and therefore only one adapter start is necessary.

have a look to https://github.com/foxthefox/ioBroker.fritzdect/tree/2.0.0-class
here I start the mock server in before() and in each it() it is necessary to manipulate the adapter settings and start the adapter, before the test cases are processed. Each device has its own it() for checking its correct creation. This is ca. 20 lines in log accompanied by 3000 lines of log for adapter start (per it()).
The log is truncated at approx.13000 lines, so the whole test can not be checked within the web window (only raw).
It works in such a way, but I think it could work like in the testAdapter.js way.

Here the simplified structure as of today:

tests.integration(path.join(__dirname, '..'), {
	defineAdditionalTests(getHarness) {
		describe('Test creation of devices', () => {
			before('start the emulation', () => {
				//start mock
			});
			it('device check 1', () => {
				return new Promise(async (resolve) => {
					const harness = getHarness();
					harness._objects.getObject('system.adapter.fritzdect.0', async (err, obj) => {
						obj.native.fritz_ip = 'http://localhost:3333';
						await harness._objects.setObjectAsync(obj._id, obj);
						// Start the adapter and wait until it has started
						await harness.startAdapterAndWait();
						harness.states.getState('fritzdect.0.DECT_087610006161.productname', function(err, state) {
							if (err) console.error(err);
							expect(state).to.exist;
							if (!state) {
								console.error('state "fritzdect.0.DECT_087610006161.productname" not set');
							} else {
								console.log('fritzdect.0.DECT_087610006161.productname      ... ' + state.val);
							}
							expect(state.val).to.exist;
							expect(state.val).to.be.equal('FRITZ!DECT 200');
						});
						// and many more states

					});
				});
			});
			it('device check 2', () => {
				return new Promise(async (resolve) => {
					const harness = getHarness();
					harness._objects.getObject('system.adapter.fritzdect.0', async (err, obj) => {
						obj.native.fritz_ip = 'http://localhost:3333';
						await harness._objects.setObjectAsync(obj._id, obj);
						// Start the adapter and wait until it has started
						await harness.startAdapterAndWait();
						harness.states.getState('fritzdect.0.DECT_087610006161.productname', function(err, state) {
							if (err) console.error(err);
							expect(state).to.exist;
							if (!state) {
								console.error('state "fritzdect.0.DECT_087610006161.productname" not set');
							} else {
								console.log('fritzdect.0.DECT_087610006161.productname      ... ' + state.val);
							}
							expect(state.val).to.exist;
							expect(state.val).to.be.equal('FRITZ!DECT 200');
						});
						// and many more states

					});
				});
			});
			// next it()
		});
	};
});

my idea:

tests.integration(path.join(__dirname, '..'), {
	defineAdditionalTests(getHarness) {
		describe('Test creation of devices', () => {
			before('start the emulation', () => {
				//start mock
				//setup harness
				const harness = getHarness();
				harness._objects.getObject('system.adapter.fritzdect.0', async (err, obj) => {
					obj.native.fritz_ip = 'http://localhost:3333';
					await harness._objects.setObjectAsync(obj._id, obj);
				});
				// Start the adapter and wait until it has started
				await harness.startAdapterAndWait();
			});
			it('device check 1', () => {
				return new Promise(async (resolve) => {
					harness.states.getState('fritzdect.0.DECT_087610006161.productname', function(err, state) {
						//tests
					});
					// and many more states
					});
				});
			});
			it('device check 2', () => {
				return new Promise(async (resolve) => {
					return new Promise(async (resolve) => {
						harness.states.getState('fritzdect.0.DECT_087610006161.productname', function(err, state) {
							//tests
						});
						// and many more states
						});
					});
				});
			// next it()
		});
	};
});

Unit tests fail when a loaded module starts with a hashbang (#!)

https://travis-ci.org/Apollon77/ioBroker.meross/jobs/504243109#L798

local error is

1) Test the adapter (in a mocked environment)
       The adapter starts in normal mode:
     /Volumes/Dev/GitHub/ioBroker.meross/node_modules/mqtt/mqtt.js:1
(function (exports, require, module, __filename, __dirname) { ((process) => {#!/usr/bin/env node
                                                                             ^

SyntaxError: Invalid or unexpected token
      at createScript (vm.js:80:10)
      at Object.runInThisContext (vm.js:139:10)
      at Module.module._compile (node_modules/@iobroker/testing/build/tests/unit/harness/loader.js:148:24)
      at Object.replaceJsLoader [as .js] (node_modules/@iobroker/testing/build/tests/unit/harness/loader.js:152:9)
      at Module.fakeRequire [as require] (node_modules/@iobroker/testing/build/tests/unit/harness/loader.js:28:16)
      at require (internal/module.js:11:18)
      at EventEmitter (node_modules/meross-cloud/index.js:8:14)
      at Object.<anonymous> (node_modules/meross-cloud/index.js:363:3)
      at Module.module._compile (node_modules/@iobroker/testing/build/tests/unit/harness/loader.js:148:24)
      at Object.replaceJsLoader [as .js] (node_modules/@iobroker/testing/build/tests/unit/harness/loader.js:152:9)
      at Module.fakeRequire [as require] (node_modules/@iobroker/testing/build/tests/unit/harness/loader.js:28:16)
      at require (internal/module.js:11:18)
      at /Volumes/Dev/GitHub/ioBroker.meross/main.js:13:21
      at Object.<anonymous> (main.js:520:3)
      at Module.module._compile (node_modules/@iobroker/testing/build/tests/unit/harness/loader.js:148:24)
      at Object.replaceJsLoader [as .js] (node_modules/@iobroker/testing/build/tests/unit/harness/loader.js:152:9)
      at require (internal/module.js:11:18)
      at Object.loadModuleInHarness (node_modules/@iobroker/testing/build/tests/unit/harness/loader.js:158:26)
      at Object.<anonymous> (node_modules/@iobroker/testing/build/tests/unit/harness/startMockAdapter.js:54:41)
      at Generator.next (<anonymous>)
      at /Volumes/Dev/GitHub/ioBroker.meross/node_modules/@iobroker/testing/build/tests/unit/harness/startMockAdapter.js:9:71
      at new Promise (<anonymous>)
      at __awaiter (node_modules/@iobroker/testing/build/tests/unit/harness/startMockAdapter.js:5:12)
      at Object.startMockAdapter (node_modules/@iobroker/testing/build/tests/unit/harness/startMockAdapter.js:27:12)
      at Context.<anonymous> (node_modules/@iobroker/testing/build/tests/unit/index.js:43:114)
      at Generator.next (<anonymous>)
      at /Volumes/Dev/GitHub/ioBroker.meross/node_modules/@iobroker/testing/build/tests/unit/index.js:9:71
      at new Promise (<anonymous>)
      at __awaiter (node_modules/@iobroker/testing/build/tests/unit/index.js:5:12)
      at Context.<anonymous> (node_modules/@iobroker/testing/build/tests/unit/index.js:39:20)

mockAdapterCore.controllerDir not working as expected in some situations

The member "controllerDir" of the mocked adapterCore points to a wrong directory in my setup.

My setup is as follows:
ioBroker Folder: D:\ioBroker\KMProduktiv\
the adapter code is in D:\ioBroker\KMProduktiv\iobroker.lovelace
it is linked to node_modules by npm link, i.e. D:\iobroker\KMProduktiv\node_modules\iobroker.lovelace -> C:\Users\achim\AppData\Roaming\npm\node_modules\iobroker.lovelace -> D:\iobroker\KMProduktiv\ioBroker.lovelace

When running npm run test:unit in D:\ioBroker\KM\iobroker.lovelace it is more or less exptected that controllerDir fails to point to the correct controller dir by a look at the code. But for some reason it fails with the same error when running in D:\ioBroker\KMProduktiv\node_modules\iobroker.lovelace, in both cases the controllerDir will be D:\iobroker\KMProduktiv\iobroker.js-controller

So in the setup using npm link the mocked adapter core points to the wrong js-controller dir. Not sure how to fix that.

The location of the adapter code is restricted to D:\ioBroker\KMProduktiv\iobroker.lovelace for similar reasons, because otherwise the js-controller can not be found (also it can not be in D:\ioBroker\KMProduktiv\node_modules\iobroker.lovelace because of the .git folder, which will prevent NPM from working). The original code of finding js-controller looks very different. May it should be more similar in the mockCase?

Package tests fail with `TypeError: iopackContent.common.titleLang is not iterable`

After a fresh (typescript or javascript) adapter creation with npx @iobroker/create-adapter, the testing fails with a TypeError.

npm run test:package fails with the following output:

npm run test:package

> [email protected] test:package
> mocha test/package --exit



  Validate the package files
    Ensure they are readable
      package.json
        ✓ exists
        ✓ contains valid JSON
        ✓ is an object
      io-package.json
        ✓ exists
        ✓ contains valid JSON
        ✓ is an object
    Check contents of package.json
      ✓ The property "name" exists
      ✓ The property "version" exists
      ✓ The property "description" exists
      ✓ The property "author" exists
      ✓ The property "license" exists
      ✓ The property "main" exists
      ✓ The property "repository" exists
      ✓ The property "repository.type" exists
      ✓ The package name is correct
      ✓ The repository type is "git"
    Check contents of io-package.json
      ✓ The property "common.name" exists
      ✓ The property "common.titleLang" exists
      ✓ The property "common.version" exists
      ✓ The property "common.news" exists
      ✓ The property "common.desc" exists
      ✓ The property "common.icon" exists
      ✓ The property "common.extIcon" exists
      ✓ The property "common.license" exists
      ✓ The property "common.type" exists
      ✓ The property "common.authors" exists
      ✓ The property "native" exists
      ✓ The title does not contain "adapter" or "iobroker"
      ✓ titleLang is an object to support multiple languages
      1) titleLang does not contain "adapter" or "iobroker"
      ✓ The description is an object to support multiple languages
      ✓ common.authors is an array that is not empty
      ✓ common.news is an object that contains maximum 20 entries
      ✓ Materialize is supported
    Compare contents of package.json and io-package.json
      ✓ The name matches
      ✓ The version matches
      ✓ The license matches


  36 passing (43ms)
  1 failing

  1) Validate the package files
       Check contents of io-package.json
         titleLang does not contain "adapter" or "iobroker":
     TypeError: iopackContent.common.titleLang is not iterable
      at Context.<anonymous> (node_modules/@iobroker/testing/build/tests/packageFiles/index.js:143:58)
      at processImmediate (internal/timers.js:456:21)



npm ERR! code 1
npm ERR! path /home/thomas/projects/ioBroker.auto_strom_ts
npm ERR! command failed
npm ERR! command sh -c mocha test/package --exit

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/thomas/.npm/_logs/2021-03-13T21_11_43_889Z-debug.log

maybe related to #385 ?

ObjectChange only emits the id as string

When listening for objectChanges via

harness.on('objectChange', obj =>

obj is only a string representing the changed object id. Probably it should be the whole object.

Typescript & Unit Testing

Hi,
I want to write my first adapter for ioBroker. I want also to write unit tests for my adapter to check if states will be creating right and check if it handle right but I get it not working.

My idea is that I need this Module to mock the adapter and js-controller. Is this right?

I created my adapter with the "npx @iobroker/create-adapter" and I select the Typescript variant.

If I change the src/main.test.ts with the example from this repo and I run it there a lot of errors like:
build/main.js:27:17 - error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.

I think the problem is that the builded files (javascript) will be executed and not the src files from the adapter.
If I turned on the Debug Mode I get this entry file:
testing:unit:adapterTools => found build/main.js +1ms
Should the entry file for Typescript not this src/main.ts?

Is this a Bug or what is my mistake?

I hope someone can me help :)

Best regards
xDGeForcexD

PS: I changed the example code a little bit:

import { tests, utils } from "@iobroker/testing";
import path = require("path");

tests.unit(path.join(__dirname, ".."), {
	//     ~~~~~~~~~~~~~~~~~~~~~~~~~
	// This should be the adapter's root directory

	// Define your own tests inside defineAdditionalTests
	defineAdditionalTests() {
		// Create mocks and asserts
		const { adapter, database } = utils.unit.createMocks({});

		describe("my test", () => {
			afterEach(() => {
				// The mocks keep track of all method invocations - reset them after each single test
				adapter.resetMockHistory();
				// We want to start each test with a fresh database
				database.clear();
			});

			it("works", () => {
				// Do something that should be tested
				console.log(database.getObjects("*"));
			});
		});
	},
});

Integration tests don't work on Windows past first testcase

Hi,
when writing some AdditionalTests I found that the Redis service seems to break (Travis-CI job: https://travis-ci.org/github/Excodibur/ioBroker.schwoerer-ventcube/jobs/725840082):

The adapter started successfully.
    √ The adapter starts (5652ms)
 Objects 127.0.0.1:50062 Redis Socket error: Error: read ECONNRESET
 Objects 127.0.0.1:50063 Redis Socket error: Error: read ECONNRESET
 Objects 127.0.0.1:50064 Redis Socket error: Error: read ECONNRESET
 States 127.0.0.1:50065 Redis Socket error: Error: read ECONNRESET
 States 127.0.0.1:50066 Redis Socket error: Error: read ECONNRESET
 States 127.0.0.1:50067 Redis Socket error: Error: read ECONNRESET
    Adapter core functions
 Objects DB uses file write interval of 5000 ms

And for the next testcase this results in the following:

      1) should read correct values from Ventcube mock
 Objects 127.0.0.1:50069 Redis Socket error: Error: read ECONNRESET
 Objects 127.0.0.1:50070 Redis Socket error: Error: read ECONNRESET
 Objects 127.0.0.1:50071 Redis Socket error: Error: read ECONNRESET
 States 127.0.0.1:50072 Redis Socket error: Error: read ECONNRESET
 States 127.0.0.1:50073 Redis Socket error: Error: read ECONNRESET
 States 127.0.0.1:50074 Redis Socket error: Error: read ECONNRESET
 Objects DB uses file write interval of 5000 ms

Weirdly my mock-service I start as a background-service before the first testcase also works for that specific testcase, but is not reachable anymore for the second testcase. On Linux & OSX it works flawlessly, though.

Actually I see a similar behaviour also in other adapter integration tests, e.g. https://travis-ci.org/github/StrathCole/ioBroker.tahoma/jobs/668379396, so I guess it is not an isolated problem, but perhaps something to process-handling within test-harness or some Windows process handling problem.

Please give it a look.

How I use two tests.unit in one project

Hi,

I need write unit test for correct sync object iobroker database with my config from index_m.html and correct change state in object tree after my adapter receive data packet from low-level device. I decide write this tests in separately files. I created two files with same code:

tests.unit(path.join(__dirname, '..'), {
	allowedExitCodes: [11],
	additionalMockedModules: {
		'serialport': FakeSerialPort
	},
...

When I run tests my adapter crashed with exception:

at Object. (node_modules/@iobroker/testing/build/tests/unit/index.js:91:21)
at Generator.next ()
at /home/pavel/Development/nordica/iobroker.noolitef/node_modules/@iobroker/testing/build/tests/unit/index.js:9:71
at new Promise ()
at __awaiter (node_modules/@iobroker/testing/build/tests/unit/index.js:5:12)
at Suite.describe (node_modules/@iobroker/testing/build/tests/unit/index.js:53:66)
at Object.testAdapterWithMocks [as unit] (node_modules/@iobroker/testing/build/tests/unit/index.js:53:5)
at Object. (test/unit-objectsync.js:10:7)
at require (internal/module.js:11:18)
at Array.forEach ()
at startup (bootstrap_node.js:204:16)
at bootstrap_node.js:625:3

How I can fix?

Thanks

integration: restore objects backup after all tests are run

If you run integration tests on a local system multiple times in a row (for example in order to test them), always the same setup is used ( temp\test-iobroker.adatername ). If you do not clean up the temp directory manually, iobroker and also the db-files will be reused on the next test run.
This leads to the situation that database changes from the last integration test persist between multiple test runs (and may interfere with them). So I vote for an after() clause that restores the backup that is already done during start. Or move the restore of the backup into "afterEach".
Maybe the restore in "afterEach" is even better, because currently the first restore is not necessary, if I understand it correctly.

[Unit Testing] adapter.getDevicesAsync.returns results in TypeError: Cannot read property 'returns' of undefined

[Unit Testing] adapter.getDevicesAsync.returns results in TypeError: Cannot read property 'returns' of undefined

unit.js content :

const path = require('path');
const { tests } = require('@iobroker/testing');

// Run unit tests - See https://github.com/ioBroker/testing for a detailed explanation and further options
tests.unit(path.join(__dirname, ".."),{
    defineMockBehavior(db, adapter) {
        adapter.getDevicesAsync.returns([
            {
              "from": "system.adapter.wled.0",
              "user": "system.user.admin",
              "ts": 1584734463218,
              "common": {
                "name": "Wookamer"
              },
              "native": {
                "ip": "192.168.10.94",
                "mac": "cc50e35b8323",
                "name": "Wookamer"
              },
              "acl": {
                "object": 1636,
                "owner": "system.user.admin",
                "ownerGroup": "system.group.administrator"
              },
              "_id": "wled.0.cc50e35b832b",
              "type": "device"
            },
            {
              "type": "device",
              "common": {
                "name": "WLED"
              },
              "native": {
                "ip": "192.168.10.39",
                "mac": "840d8e8a7eb3",
                "name": "WLED"
              },
              "from": "system.adapter.wled.0",
              "user": "system.user.admin",
              "ts": 1584739064300,
              "_id": "wled.0.840d8e8a7eb3",
              "acl": {
                "object": 1636,
                "owner": "system.user.admin",
                "ownerGroup": "system.group.administrator"
              }
            }
          ]);
    }
});

In unit test createMocks create wrong adapter

Hi,

I try use code from README.md sample in unit test (not integration)

const { database, adapter } = utils.unit.createMocks();

In adapter variable I see adapter with "test.0" name, but I expected my adapter ("noolitef.0") to be created.
It`s bug or feature? What different tests purpose for iobroker development between unit and integration tests?

Thanks

utils.unit.createMocks() throws Exception TypeError: Cannot redefine property: readyHandler on second call

Issue description

My adapter logic is split into several classes each of them with its own test cases. According to the README I should call utils.unit.createMocks() to create my own set of mock objects. That works for the first file with test cases but in the second file I have to create the mock objects again and I receive an exception TypeError: Cannot redefine property: readyHandler.

Expected behaviour

Subsequent calls to utils.unit.createMocks() should work without throwing an exception.

Steps to reproduce

  1. Generate a new Typescript-based adapter with the template generator CLI.
  2. Overwrite the file main.test.ts with the code below.
/**
 * This is a dummy TypeScript test file using chai and mocha
 *
 * It's automatically excluded from npm and its build output is excluded from both git and npm.
 * It is advised to test all your modules with accompanying *.test.ts-files
 */

import { expect } from "chai";
const { utils } = require("@iobroker/testing");
// import { functionToTest } from "./moduleToTest";

describe("module to test => function to test", () => {
	// initializing logic
	const expected = 5;

	it(`should return ${expected}`, () => {
		const result = 5;
		// assign result a value from functionToTest
		expect(result).to.equal(expected);
		// or using the should() syntax
		result.should.equal(expected);
	});

	it(`shouldn't throw an exception`, () => {
		expect(function () {
			const { database, adapter } = utils.unit.createMocks();
		}).not.to.throw();
	});

	it(`shouldn't throw an exception, neither`, () => {
		expect(function () {
			const { database, adapter } = utils.unit.createMocks();
		}).not.to.throw();
	});
});

// ... more test suites => describe
  1. Run the test with test:ts script -> The first two tests succeed, the last one fails.

Analyzed so far

The properties are bound to the function createAdapterMock, I'm not sure, if this is the intended behaviour. A simple fix probably would be to set the configurable attribute to true for the properties in the call to Object.defineProperties

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.