@risleylima/escpos 0.0.13 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,128 @@
1
+ 'use strict';
2
+
3
+ const Printer = require('../../src/printer');
4
+
5
+ describe('Printer Integration', () => {
6
+ let printer;
7
+ let mockAdapter;
8
+
9
+ beforeEach(() => {
10
+ mockAdapter = {
11
+ write: jest.fn().mockResolvedValue(true),
12
+ close: jest.fn().mockResolvedValue(true)
13
+ };
14
+ printer = new Printer(mockAdapter);
15
+ });
16
+
17
+ describe('Complete Print Flow', () => {
18
+ it('should print a complete receipt', async () => {
19
+ printer
20
+ .hardware('init')
21
+ .beep(1, 1)
22
+ .encode(860)
23
+ .size(2, 2)
24
+ .align('ct')
25
+ .textln('TEST RECEIPT')
26
+ .size(1, 1)
27
+ .align('lt')
28
+ .textln('Item 1: R$ 10,00')
29
+ .textln('Item 2: R$ 20,00')
30
+ .align('rt')
31
+ .textln('Total: R$ 30,00')
32
+ .align('lt')
33
+ .drawLine()
34
+ .cut(true);
35
+
36
+ await printer.flush();
37
+
38
+ expect(mockAdapter.write).toHaveBeenCalled();
39
+ const writtenBuffer = mockAdapter.write.mock.calls[0][0];
40
+ expect(writtenBuffer.length).toBeGreaterThan(0);
41
+ });
42
+
43
+ it('should print receipt with barcode', async () => {
44
+ printer
45
+ .hardware('init')
46
+ .align('ct')
47
+ .textln('PRODUCT')
48
+ .barcode('123456789012', 'EAN13', {
49
+ width: 2,
50
+ height: 50,
51
+ position: 'BLW'
52
+ })
53
+ .cut(true);
54
+
55
+ await printer.flush();
56
+
57
+ expect(mockAdapter.write).toHaveBeenCalled();
58
+ });
59
+
60
+ it('should handle multiple prints in sequence', async () => {
61
+ // First print
62
+ printer
63
+ .hardware('init')
64
+ .textln('Print 1')
65
+ .cut(true);
66
+ await printer.flush();
67
+
68
+ // Second print
69
+ printer
70
+ .hardware('init')
71
+ .textln('Print 2')
72
+ .cut(true);
73
+ await printer.flush();
74
+
75
+ expect(mockAdapter.write).toHaveBeenCalledTimes(2);
76
+ });
77
+ });
78
+
79
+ describe('Complex Formatting', () => {
80
+ it('should handle mixed formatting', async () => {
81
+ printer
82
+ .align('ct')
83
+ .size(2, 2)
84
+ .style('B')
85
+ .textln('BOLD TITLE')
86
+ .style('NORMAL')
87
+ .size(1, 1)
88
+ .align('lt')
89
+ .textln('Normal text')
90
+ .style('U')
91
+ .textln('Underlined text')
92
+ .style('NORMAL')
93
+ .cut(true);
94
+
95
+ await printer.flush();
96
+ expect(mockAdapter.write).toHaveBeenCalled();
97
+ });
98
+
99
+ it('should handle encoding changes', async () => {
100
+ printer
101
+ .encode('UTF-8')
102
+ .textln('UTF-8 Text')
103
+ .encode('GB18030')
104
+ .textln('GB18030 Text')
105
+ .cut(true);
106
+
107
+ await printer.flush();
108
+ expect(mockAdapter.write).toHaveBeenCalled();
109
+ });
110
+ });
111
+
112
+ describe('Error Handling', () => {
113
+ it('should handle adapter write errors', async () => {
114
+ mockAdapter.write.mockRejectedValueOnce(new Error('Write failed'));
115
+
116
+ printer.text('Test');
117
+ await expect(printer.flush()).rejects.toThrow('Write failed');
118
+ });
119
+
120
+ it('should handle adapter close errors gracefully', async () => {
121
+ mockAdapter.close.mockRejectedValueOnce(new Error('Close failed'));
122
+
123
+ printer.text('Test');
124
+ await expect(printer.close()).rejects.toThrow('Close failed');
125
+ });
126
+ });
127
+ });
128
+
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ const Adapter = require('../../../src/adapter');
4
+
5
+ describe('Adapter', () => {
6
+ let adapter;
7
+
8
+ beforeEach(() => {
9
+ adapter = new Adapter();
10
+ });
11
+
12
+ it('should be an instance of EventEmitter', () => {
13
+ const EventEmitter = require('events');
14
+ expect(adapter).toBeInstanceOf(EventEmitter);
15
+ });
16
+
17
+ it('should throw NotImplementedException for connect', () => {
18
+ expect(() => adapter.connect()).toThrow(Error);
19
+ });
20
+
21
+ it('should throw NotImplementedException for open', () => {
22
+ expect(() => adapter.open()).toThrow(Error);
23
+ });
24
+
25
+ it('should throw NotImplementedException for write', () => {
26
+ expect(() => adapter.write()).toThrow(Error);
27
+ });
28
+
29
+ it('should throw NotImplementedException for close', () => {
30
+ expect(() => adapter.close()).toThrow(Error);
31
+ });
32
+
33
+ it('should throw NotImplementedException for read', () => {
34
+ expect(() => adapter.read()).toThrow(Error);
35
+ });
36
+
37
+ it('should copy properties from provided adapter', () => {
38
+ const mockAdapter = {
39
+ connect: jest.fn(),
40
+ write: jest.fn(),
41
+ customProp: 'test'
42
+ };
43
+
44
+ const adapter = new Adapter(mockAdapter);
45
+ expect(adapter.customProp).toBe('test');
46
+ expect(adapter.connect).toBe(mockAdapter.connect);
47
+ });
48
+ });
49
+
@@ -0,0 +1,224 @@
1
+ 'use strict';
2
+
3
+ const Serial = require('../../../src/serial-adapter');
4
+ const { SerialPort } = require('serialport');
5
+
6
+ // Mock serialport (v13 API - uses Promises)
7
+ jest.mock('serialport', () => {
8
+ const mockPort = {
9
+ isOpen: false,
10
+ open: jest.fn().mockResolvedValue(undefined),
11
+ close: jest.fn().mockResolvedValue(undefined),
12
+ write: jest.fn().mockResolvedValue(undefined),
13
+ flush: jest.fn().mockResolvedValue(undefined),
14
+ drain: jest.fn().mockResolvedValue(undefined),
15
+ on: jest.fn(),
16
+ removeListener: jest.fn()
17
+ };
18
+
19
+ // Update isOpen when open/close are called
20
+ const originalOpen = mockPort.open;
21
+ mockPort.open = jest.fn().mockImplementation(async () => {
22
+ mockPort.isOpen = true;
23
+ return originalOpen();
24
+ });
25
+
26
+ const originalClose = mockPort.close;
27
+ mockPort.close = jest.fn().mockImplementation(async () => {
28
+ mockPort.isOpen = false;
29
+ return originalClose();
30
+ });
31
+
32
+ const SerialPortConstructor = jest.fn().mockImplementation((options) => {
33
+ return mockPort;
34
+ });
35
+
36
+ // Attach list as static method to SerialPort constructor
37
+ SerialPortConstructor.list = jest.fn().mockResolvedValue([
38
+ { path: '/dev/ttyUSB0' },
39
+ { path: '/dev/ttyUSB1' }
40
+ ]);
41
+
42
+ return {
43
+ SerialPort: SerialPortConstructor
44
+ };
45
+ });
46
+
47
+ describe('Serial Adapter', () => {
48
+ beforeEach(() => {
49
+ jest.clearAllMocks();
50
+ });
51
+
52
+ describe('connect', () => {
53
+ it('should connect to serial port', async () => {
54
+ const result = await Serial.connect('/dev/ttyUSB0');
55
+ expect(result).toBe(true);
56
+ expect(SerialPort).toHaveBeenCalled();
57
+ });
58
+
59
+ it('should verify port exists', async () => {
60
+ await Serial.connect('/dev/ttyUSB0');
61
+ expect(SerialPort.list).toHaveBeenCalled();
62
+ });
63
+
64
+ it('should throw error if port does not exist', async () => {
65
+ await expect(Serial.connect('/dev/invalid')).rejects.toThrow('The specified port does not exist!');
66
+ });
67
+
68
+ it('should emit connect event', (done) => {
69
+ Serial.once('connect', () => {
70
+ done();
71
+ });
72
+ Serial.connect('/dev/ttyUSB0');
73
+ });
74
+ });
75
+
76
+ describe('open', () => {
77
+ beforeEach(async () => {
78
+ await Serial.connect('/dev/ttyUSB0');
79
+ });
80
+
81
+ it('should open port if closed', async () => {
82
+ const result = await Serial.open();
83
+ expect(result).toBe(true);
84
+
85
+ // Verify port.open was called
86
+ const mockPort = SerialPort.mock.results[0].value;
87
+ expect(mockPort.open).toHaveBeenCalled();
88
+ });
89
+
90
+ it('should return true if already open', async () => {
91
+ // Get the mock port and set it as already open
92
+ const mockPort = SerialPort.mock.results[0].value;
93
+ const previousCallCount = mockPort.open.mock.calls.length;
94
+ mockPort.isOpen = true;
95
+
96
+ const result = await Serial.open();
97
+ expect(result).toBe(true);
98
+
99
+ // Verify port.open was NOT called again (call count should be the same)
100
+ // Since isOpen is true, the code should return early without calling open()
101
+ expect(mockPort.open.mock.calls.length).toBe(previousCallCount);
102
+ });
103
+ });
104
+
105
+ describe('write', () => {
106
+ beforeEach(async () => {
107
+ await Serial.connect('/dev/ttyUSB0');
108
+ await Serial.open();
109
+ });
110
+
111
+ it('should write data to port', async () => {
112
+ const testData = Buffer.from('test', 'ascii');
113
+ const result = await Serial.write(testData);
114
+ expect(result).toBe(true);
115
+
116
+ // Verify port.write was called with correct data
117
+ const mockPort = SerialPort.mock.results[0].value;
118
+ expect(mockPort.write).toHaveBeenCalledWith(testData);
119
+ });
120
+
121
+ it('should drain port after write', async () => {
122
+ const testData = Buffer.from('test', 'ascii');
123
+ await Serial.write(testData);
124
+
125
+ const mockPort = SerialPort.mock.results[0].value;
126
+ expect(mockPort.write).toHaveBeenCalled();
127
+ expect(mockPort.drain).toHaveBeenCalled();
128
+ });
129
+ });
130
+
131
+ describe('close', () => {
132
+ beforeEach(async () => {
133
+ await Serial.connect('/dev/ttyUSB0');
134
+ await Serial.open();
135
+ });
136
+
137
+ it('should close port', async () => {
138
+ const result = await Serial.close();
139
+ expect(result).toBe(true);
140
+
141
+ // Verify close sequence was called
142
+ const mockPort = SerialPort.mock.results[0].value;
143
+ expect(mockPort.flush).toHaveBeenCalled();
144
+ expect(mockPort.drain).toHaveBeenCalled();
145
+ expect(mockPort.close).toHaveBeenCalled();
146
+ });
147
+
148
+ it('should flush before closing', async () => {
149
+ await Serial.close();
150
+
151
+ const mockPort = SerialPort.mock.results[0].value;
152
+ expect(mockPort.flush).toHaveBeenCalled();
153
+ expect(mockPort.drain).toHaveBeenCalled();
154
+ expect(mockPort.close).toHaveBeenCalled();
155
+ });
156
+
157
+ it('should use default timeout of 50ms', async () => {
158
+ await Serial.close();
159
+ // Should complete without error
160
+ expect(true).toBe(true);
161
+ });
162
+
163
+ it('should use custom timeout', async () => {
164
+ await Serial.close(100);
165
+ // Should complete without error
166
+ expect(true).toBe(true);
167
+ });
168
+
169
+ it('should emit close event', async () => {
170
+ let eventReceived = false;
171
+ const promise = new Promise((resolve) => {
172
+ Serial.once('close', () => {
173
+ eventReceived = true;
174
+ resolve();
175
+ });
176
+ });
177
+
178
+ expect(Serial.listenerCount('close')).toBe(1);
179
+
180
+ await Serial.close();
181
+
182
+ await Promise.race([
183
+ promise,
184
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Close event not emitted within timeout')), 1000))
185
+ ]);
186
+
187
+ expect(eventReceived).toBe(true);
188
+ });
189
+ });
190
+
191
+ describe('disconnect', () => {
192
+ beforeEach(async () => {
193
+ await Serial.connect('/dev/ttyUSB0');
194
+ });
195
+
196
+ it('should disconnect (calls close)', async () => {
197
+ const result = await Serial.disconnect();
198
+ expect(result).toBe(true);
199
+ });
200
+ });
201
+
202
+ describe('read', () => {
203
+ beforeEach(async () => {
204
+ await Serial.connect('/dev/ttyUSB0');
205
+ await Serial.open();
206
+ });
207
+
208
+ it('should read data from port', async () => {
209
+ const mockPort = SerialPort.mock.results[0].value;
210
+ const testData = Buffer.from('response', 'ascii');
211
+
212
+ // Mock data event
213
+ mockPort.on.mockImplementation((event, handler) => {
214
+ if (event === 'data') {
215
+ setTimeout(() => handler(testData), 10);
216
+ }
217
+ });
218
+
219
+ const data = await Serial.read();
220
+ expect(Buffer.isBuffer(data)).toBe(true);
221
+ });
222
+ });
223
+ });
224
+