Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a "back door" to mock port bindings so we can emulate serial devices #2734

Open
jmbldwn opened this issue Nov 25, 2023 · 1 comment

Comments

@jmbldwn
Copy link

jmbldwn commented Nov 25, 2023

馃挜 Proposal

What feature you'd like to see

Mocking currently only supports echoing and explicit reading of history once a port is opened. Provide a "back end" stream interface so we can emulate actual serial devices connected to mock ports.

Motivation

I am building unit tests for the code I write that talks to real serial port devices. Unit tests can't easily run in an environment where there is physical hardware, so we need a way to not only emulate the port, but the protocol the device implements over it.

Pitch

I currently have no unit tests for any of the code I wrote that uses SerialPort to talk to hardware devices. For example, I have a power meter (PZEM), an M-Bus interface, some custom Arduino devices, including a burning man LED display, and several lab meters that run over serial. I want to write emulators for the protocols my devices use so I can create unit tests that can run under CI, in my case using Jest.

The mocking interface falls just short of letting me do what I need. I can substitute SerialPortMock in place of SerialPort using Jest mocking, which lets me create mock ports ('/dev/ROBOT') that my target code will try to open. My target code can open one of those ports, but I have no way of interacting with my target code as if it were talking to a real device.

One approach is to provide a stream interface from a mock port (MockBinding.create...) which I can use to listen for data my target code is sending, and send responses to it. This stream interface would talk to any instance of SerialPortMock that opens that ports, so it would persist across port instances.

I could also extend MockPortBinding to implement my device class by overriding write, but there's no way to get MockBinding.createPort to use my class. If I could specify the port binding to be returned by createPort that would do the trick.

I can't extend MockBinding because it's not a class, and I'd end up rewriting most of what it does.

I defer to the core implementers on the best way to achieve this, and indeed if I'm missing something let me know.

@lilulu2023
Copy link

I experienced the same situation and workout an ugly workaround, hopefully this will help anyone who needs it

port.on('open', () => {
    port.port.write = async (buffer) => {
        this.writeOperation = Promise.resolve(buffer).then(buff => port.port.emitData(buff)); // do something before emit
        return this.writeOperation;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants