@risleylima/escpos 0.2.1 → 1.0.1

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.
Files changed (107) hide show
  1. package/README.md +116 -755
  2. package/dist/adapter/index.d.ts +29 -0
  3. package/dist/adapter/index.d.ts.map +1 -0
  4. package/dist/adapter/index.js +25 -0
  5. package/dist/adapter/index.js.map +1 -0
  6. package/dist/index.d.ts +14 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +25 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/network-adapter/index.d.ts +24 -0
  11. package/dist/network-adapter/index.d.ts.map +1 -0
  12. package/dist/network-adapter/index.js +263 -0
  13. package/dist/network-adapter/index.js.map +1 -0
  14. package/dist/printer/commands-types.d.ts +37 -0
  15. package/dist/printer/commands-types.d.ts.map +1 -0
  16. package/dist/printer/commands-types.js +63 -0
  17. package/dist/printer/commands-types.js.map +1 -0
  18. package/dist/printer/commands.d.ts +169 -0
  19. package/dist/printer/commands.d.ts.map +1 -0
  20. package/dist/printer/commands.js +192 -0
  21. package/dist/printer/commands.js.map +1 -0
  22. package/dist/printer/image-loader.d.ts +17 -0
  23. package/dist/printer/image-loader.d.ts.map +1 -0
  24. package/dist/printer/image-loader.js +462 -0
  25. package/dist/printer/image-loader.js.map +1 -0
  26. package/dist/printer/image.d.ts +43 -0
  27. package/dist/printer/image.d.ts.map +1 -0
  28. package/dist/printer/image.js +132 -0
  29. package/dist/printer/image.js.map +1 -0
  30. package/dist/printer/index.d.ts +158 -0
  31. package/dist/printer/index.d.ts.map +1 -0
  32. package/dist/printer/index.js +703 -0
  33. package/dist/printer/index.js.map +1 -0
  34. package/dist/printer/profiles/bematech/mp4200th.d.ts +13 -0
  35. package/dist/printer/profiles/bematech/mp4200th.d.ts.map +1 -0
  36. package/dist/printer/profiles/bematech/mp4200th.js +29 -0
  37. package/dist/printer/profiles/bematech/mp4200th.js.map +1 -0
  38. package/dist/printer/profiles/custom/bematech-mp4200th.d.ts +13 -0
  39. package/dist/printer/profiles/custom/bematech-mp4200th.d.ts.map +1 -0
  40. package/dist/printer/profiles/custom/bematech-mp4200th.js +21 -0
  41. package/dist/printer/profiles/custom/bematech-mp4200th.js.map +1 -0
  42. package/dist/printer/profiles/custom/vkp80iii.d.ts +19 -0
  43. package/dist/printer/profiles/custom/vkp80iii.d.ts.map +1 -0
  44. package/dist/printer/profiles/custom/vkp80iii.js +87 -0
  45. package/dist/printer/profiles/custom/vkp80iii.js.map +1 -0
  46. package/dist/printer/profiles/default.d.ts +7 -0
  47. package/dist/printer/profiles/default.d.ts.map +1 -0
  48. package/dist/printer/profiles/default.js +15 -0
  49. package/dist/printer/profiles/default.js.map +1 -0
  50. package/dist/printer/profiles/index.d.ts +41 -0
  51. package/dist/printer/profiles/index.d.ts.map +1 -0
  52. package/dist/printer/profiles/index.js +98 -0
  53. package/dist/printer/profiles/index.js.map +1 -0
  54. package/dist/printer/profiles/merge.d.ts +7 -0
  55. package/dist/printer/profiles/merge.d.ts.map +1 -0
  56. package/dist/printer/profiles/merge.js +58 -0
  57. package/dist/printer/profiles/merge.js.map +1 -0
  58. package/dist/printer/profiles/types.d.ts +99 -0
  59. package/dist/printer/profiles/types.d.ts.map +1 -0
  60. package/dist/printer/profiles/types.js +8 -0
  61. package/dist/printer/profiles/types.js.map +1 -0
  62. package/dist/printer/utils.d.ts +9 -0
  63. package/dist/printer/utils.d.ts.map +1 -0
  64. package/dist/printer/utils.js +54 -0
  65. package/dist/printer/utils.js.map +1 -0
  66. package/dist/serial-adapter/index.d.ts +21 -0
  67. package/dist/serial-adapter/index.d.ts.map +1 -0
  68. package/dist/serial-adapter/index.js +180 -0
  69. package/dist/serial-adapter/index.js.map +1 -0
  70. package/dist/usb-adapter/index.d.ts +20 -0
  71. package/dist/usb-adapter/index.d.ts.map +1 -0
  72. package/dist/usb-adapter/index.js +264 -0
  73. package/dist/usb-adapter/index.js.map +1 -0
  74. package/package.json +42 -15
  75. package/CHANGELOG.md +0 -74
  76. package/docs/COVERAGE_ANALYSIS.md +0 -98
  77. package/docs/DEPENDENCIES_REVIEW.md +0 -127
  78. package/docs/JSDOC_REVIEW.md +0 -122
  79. package/docs/LIBRARY_OVERVIEW.md +0 -383
  80. package/docs/PRE_PUBLISH_CHECKLIST.md +0 -331
  81. package/docs/PUBLIC_API_ANALYSIS.md +0 -223
  82. package/docs/README.md +0 -37
  83. package/docs/SERIALPORT_V13_MIGRATION_COMPLETE.md +0 -127
  84. package/docs/TESTS_IMPLEMENTED.md +0 -129
  85. package/docs/USB_V2_REVIEW.md +0 -148
  86. package/docs/VERIFICATION_RESULTS.md +0 -172
  87. package/docs/VERSIONING.md +0 -102
  88. package/examples/printTest.js +0 -59
  89. package/index.js +0 -7
  90. package/jest.config.js +0 -16
  91. package/src/adapter/index.js +0 -75
  92. package/src/printer/commands.js +0 -199
  93. package/src/printer/image.js +0 -159
  94. package/src/printer/index.js +0 -621
  95. package/src/printer/utils.js +0 -58
  96. package/src/serial-adapter/index.js +0 -198
  97. package/src/usb-adapter/index.js +0 -283
  98. package/tests/README.md +0 -67
  99. package/tests/integration/printer-flow.test.js +0 -128
  100. package/tests/unit/adapters/adapter.test.js +0 -49
  101. package/tests/unit/adapters/serial-adapter.test.js +0 -238
  102. package/tests/unit/adapters/usb-adapter.test.js +0 -319
  103. package/tests/unit/image/image.test.js +0 -157
  104. package/tests/unit/printer/buffer.test.js +0 -60
  105. package/tests/unit/printer/commands.test.js +0 -109
  106. package/tests/unit/printer/printer.test.js +0 -405
  107. package/tests/unit/utils/utils.test.js +0 -96
@@ -1,198 +0,0 @@
1
- 'use strict';
2
- const { SerialPort } = require('serialport');
3
- const Adapter = require('../adapter');
4
-
5
- const debug = require('debug')('escpos:serial-adapter');
6
-
7
- const scope = {
8
- port: null,
9
- /**
10
- * Verify that a serial port exists
11
- * @private
12
- * @async
13
- * @param {String} port - Serial port path to verify
14
- * @returns {Promise<String>} Verified port path
15
- * @throws {Error} If port does not exist
16
- */
17
- verifyPort: async (port) => {
18
- let ports = await SerialPort.list();
19
- if (!ports.find((i) => i.path === port)) {
20
- throw new Error('The specified port does not exist!')
21
- }
22
- return port;
23
- }
24
- }
25
-
26
- // Create Adapter instance first, so it's the same object used internally and exported
27
- const Serial = new Adapter();
28
-
29
- /**
30
- * List all available serial ports
31
- * @async
32
- * @returns {Promise<Array<Object>>} Array of serial port objects with properties like path, manufacturer, vendorId, productId, etc.
33
- * @example
34
- * const ports = await Serial.listSerial();
35
- * console.log(ports);
36
- * // [
37
- * // { path: '/dev/ttyUSB0', manufacturer: 'FTDI', vendorId: '0403', productId: '6001' },
38
- * // { path: '/dev/ttyUSB1', manufacturer: 'Prolific', vendorId: '067b', productId: '2303' }
39
- * // ]
40
- */
41
- Serial.listSerial = async () => {
42
- return await SerialPort.list();
43
- };
44
-
45
- /**
46
- * Connect to a serial port printer
47
- * @async
48
- * @param {String} port - Serial port path (e.g., '/dev/ttyUSB0' or 'COM3')
49
- * @param {Object} [options] - Serial port options (baudRate, dataBits, etc.)
50
- * @returns {Promise<Boolean>} True if connection successful
51
- * @throws {Error} If port does not exist or cannot be opened
52
- * @fires Serial#connect
53
- * @fires Serial#close (if reconnecting)
54
- */
55
- Serial.connect = async (port, options) => {
56
- // Close existing connection if any
57
- if (scope.port) {
58
- try {
59
- await scope.port.close();
60
- } catch (e) {
61
- debug('Error closing existing port: ', e);
62
- }
63
- Serial.emit('close');
64
- }
65
-
66
- // Verify port exists
67
- const portVerified = await scope.verifyPort(port);
68
-
69
- // Create SerialPort instance (v13: no callback, autoOpen: false)
70
- scope.port = new SerialPort(Object.assign(options || {}, {
71
- path: portVerified,
72
- autoOpen: false
73
- }));
74
-
75
- // Handle errors via events
76
- scope.port.on('error', (err) => {
77
- debug('Error on Serial Port: ', err);
78
- });
79
-
80
- // Handle close event
81
- let clearPort = () => {
82
- Serial.emit('disconnect', scope.port);
83
- scope.port.removeListener('close', clearPort);
84
- scope.port = null;
85
- };
86
- scope.port.on('close', clearPort);
87
-
88
- // Open the port manually (v13: returns Promise)
89
- try {
90
- await scope.port.open();
91
- debug('Device Connected and Open!');
92
- Serial.emit('connect', scope.port);
93
- return true;
94
- } catch (err) {
95
- debug('Error Opening the Selected Port: ', err);
96
- if (scope.port) {
97
- try {
98
- await scope.port.close();
99
- } catch (closeErr) {
100
- debug('Error closing port after open failure: ', closeErr);
101
- }
102
- }
103
- throw err;
104
- }
105
- }
106
-
107
- /**
108
- * Open the serial port if it's closed
109
- * @async
110
- * @returns {Promise<Boolean>} True if port is open (or was already open)
111
- * @throws {Error} If port cannot be opened
112
- */
113
- Serial.open = async () => {
114
- if (!scope.port.isOpen) {
115
- try {
116
- await scope.port.open();
117
- debug('Device Opened!');
118
- return scope.port.isOpen;
119
- } catch (err) {
120
- throw err;
121
- }
122
- } else {
123
- debug('Device is already Opened!');
124
- return true;
125
- }
126
- };
127
-
128
- /**
129
- * Write data to the serial port
130
- * @async
131
- * @param {Buffer} data - Data buffer to send to printer
132
- * @returns {Promise<Boolean>} True if write successful
133
- * @throws {Error} If write fails
134
- */
135
- Serial.write = async (data) => {
136
- try {
137
- await scope.port.write(data);
138
- await scope.port.drain();
139
- return true;
140
- } catch (e) {
141
- throw e;
142
- }
143
- };
144
-
145
- /**
146
- * Close the serial port connection
147
- * @async
148
- * @param {Number} [timeout] - Timeout in milliseconds before closing (default: 50ms)
149
- * @returns {Promise<Boolean>} True if port closed successfully
150
- * @fires Serial#close
151
- */
152
- Serial.close = async (timeout) => {
153
- let time = Number(timeout);
154
- if (Number.isNaN(time)) {
155
- time = 50;
156
- }
157
-
158
- try {
159
- await scope.port.flush();
160
- await new Promise(resolve => setTimeout(resolve, time));
161
- await scope.port.drain();
162
- await scope.port.close();
163
- // Emit event synchronously - this ensures listeners are called immediately
164
- Serial.emit('close');
165
- return true;
166
- } catch (e) {
167
- debug('Error while closing device: ', e);
168
- // Emit event synchronously even on error - this ensures listeners are called immediately
169
- Serial.emit('close');
170
- return true; // Still resolve to allow cleanup
171
- }
172
- }
173
-
174
- /**
175
- * Disconnect from the serial port (calls close internally)
176
- * @param {Number} [timeout] - Timeout in milliseconds before closing (default: 50ms)
177
- * @returns {Promise<Boolean>} True if disconnection successful
178
- */
179
- Serial.disconnect = (timeout) => {
180
- return Serial.close(timeout);
181
- }
182
-
183
- /**
184
- * Read data from the serial port
185
- * @returns {Promise<Buffer>} Data received from the port
186
- */
187
- Serial.read = () => {
188
- return new Promise((resolve, reject) => {
189
- let dataHandler = (data) => {
190
- scope.port.removeListener('data', dataHandler);
191
- resolve(data);
192
- }
193
- scope.port.on('data', dataHandler);
194
- });
195
- };
196
-
197
- // Serial is already an Adapter instance, so export it directly
198
- module.exports = Serial;
@@ -1,283 +0,0 @@
1
- 'use strict'
2
- const Adapter = require('../adapter');
3
- const usb = require('usb');
4
- const os = require('os');
5
-
6
- const debug = require('debug')('escpos:usb-adapter');
7
-
8
- const scope = {
9
- device: null,
10
- endpoint: null
11
- }
12
-
13
- /**
14
- * [USB Class Codes ]
15
- * @type {Object}
16
- * @docs http://www.usb.org/developers/defined_class
17
- */
18
- const IFACE_CLASS = {
19
- AUDIO: 0x01,
20
- HID: 0x03,
21
- PRINTER: 0x07,
22
- HUB: 0x09
23
- };
24
-
25
- // Create Adapter instance first, so it's the same object used internally and exported
26
- const USB = new Adapter();
27
-
28
- /**
29
- * List all available USB printer devices
30
- * @async
31
- * @returns {Promise<Array>} Array of USB printer devices with manufacturer and product information
32
- */
33
- USB.listUSB = async () => {
34
- const devices = usb.getDeviceList().filter((device) => {
35
- try {
36
- // In v2, we need to check configDescriptor for interface class
37
- const configDescriptor = device.configDescriptor;
38
- if (!configDescriptor || !configDescriptor.interfaces) {
39
- return false;
40
- }
41
- // configDescriptor.interfaces is an array of arrays (alternate settings)
42
- return configDescriptor.interfaces.some((ifaceArray) => {
43
- return ifaceArray.some((iface) => {
44
- return iface.bInterfaceClass === IFACE_CLASS.PRINTER;
45
- });
46
- });
47
- } catch (e) {
48
- debug('Error while get device info: ', e);
49
- return false;
50
- }
51
- });
52
-
53
- let retorno = [];
54
-
55
- /**
56
- * Get string descriptor from USB device
57
- * @private
58
- * @async
59
- * @param {Object} device - USB device object
60
- * @param {Number} type - Descriptor type index
61
- * @returns {Promise<String|Boolean>} Descriptor string or false on error
62
- */
63
- const getDescriptor = async (device, type) => {
64
- try {
65
- await device.open();
66
- const data = await device.getStringDescriptor(type);
67
- await device.close();
68
- return data;
69
- } catch (e) {
70
- debug('Error while read device description: ', e);
71
- try {
72
- await device.close();
73
- } catch (closeErr) {
74
- // Ignore close errors
75
- }
76
- return false;
77
- }
78
- };
79
-
80
- for (let device of devices) {
81
- device.manufacturer = await getDescriptor(device, device.deviceDescriptor.iManufacturer);
82
- device.product = await getDescriptor(device, device.deviceDescriptor.iProduct);
83
- if (device.manufacturer && device.product) {
84
- retorno.push(device);
85
- }
86
- }
87
-
88
- return retorno;
89
- };
90
-
91
- /**
92
- * Connect to a USB printer device
93
- * @async
94
- * @param {Number} [vid] - Vendor ID (optional, if not provided, uses first available printer)
95
- * @param {Number} [pid] - Product ID (optional, if not provided, uses first available printer)
96
- * @returns {Promise<Boolean>} True if connection successful
97
- * @throws {Error} If printer cannot be found
98
- * @fires USB#connect
99
- */
100
- USB.connect = async (vid, pid) => {
101
- scope.device = null;
102
- scope.endpoint = null;
103
- if (vid && pid) {
104
- scope.device = usb.findByIds(vid, pid);
105
- }else{
106
- let devices = await USB.listUSB();
107
- if(devices && devices.length)
108
- scope.device = devices[0];
109
- }
110
-
111
- if (!scope.device) {
112
- throw new Error("Cannot find printer!");
113
- }
114
- USB.emit('connect', scope.device);
115
-
116
- usb.on('detach', (device) => {
117
- if (device === scope.device) {
118
- debug('Device Unplugged!');
119
- USB.emit('detach');
120
- scope.device = null;
121
- }
122
- });
123
-
124
- debug('Device Connected!');
125
- return true;
126
- };
127
-
128
- /**
129
- * Open the USB device and claim the printer interface
130
- * @async
131
- * @returns {Promise<Boolean>} True if device opened successfully
132
- * @throws {Error} If interfaces cannot be accessed or endpoint not found
133
- * @fires USB#connect
134
- */
135
- USB.open = async () => {
136
- await scope.device.open();
137
-
138
- // In v2, device.interfaces is a direct array of Interface objects
139
- // We need to iterate through all interfaces to find the printer interface
140
- const interfaces = scope.device.interfaces;
141
- if (!interfaces || interfaces.length === 0) {
142
- throw new Error('Cannot access device interfaces');
143
- }
144
-
145
- for (let interfaceObj of interfaces) {
146
- if (scope.endpoint) {
147
- break;
148
- }
149
-
150
- // Check if this interface is a printer interface
151
- const descriptor = interfaceObj.descriptor;
152
- if (descriptor && descriptor.bInterfaceClass !== IFACE_CLASS.PRINTER) {
153
- continue;
154
- }
155
-
156
- // Claim interface (required on all platforms)
157
- if ("win32" !== os.platform()) {
158
- // On Linux/macOS, detach kernel driver first if active
159
- if (interfaceObj.isKernelDriverActive()) {
160
- try {
161
- await interfaceObj.detachKernelDriver();
162
- } catch (e) {
163
- throw new Error(`[ERROR] Could not detach kernel driver: ${e.message}`);
164
- }
165
- }
166
- }
167
- // Claim interface (required on all platforms before using endpoints)
168
- await interfaceObj.claim();
169
-
170
- for (let endpoint of interfaceObj.endpoints) {
171
- if (scope.endpoint) {
172
- break;
173
- } else if (endpoint.direction === 'out') {
174
- scope.endpoint = endpoint;
175
- USB.emit('connect', scope.device);
176
- debug('Device Opened!');
177
- }
178
- }
179
- }
180
-
181
- if (!scope.endpoint) {
182
- throw new Error('Can not find endpoint from printer');
183
- }
184
- return true;
185
- };
186
-
187
- /**
188
- * Close the USB device connection and release interfaces
189
- * @async
190
- * @returns {Promise<Boolean>} True if device closed successfully
191
- * @fires USB#close
192
- */
193
- USB.close = async () => {
194
- const device = scope.device; // Save device reference before cleanup
195
-
196
- if (scope.device) {
197
- try {
198
- // Release interfaces before closing
199
- // Only release the interface we actually claimed
200
- if (scope.endpoint && scope.endpoint.interface) {
201
- const interfaceObj = scope.endpoint.interface;
202
- try {
203
- // Check if interface is still valid and was claimed
204
- if (interfaceObj && typeof interfaceObj.release === 'function') {
205
- await interfaceObj.release();
206
- }
207
- } catch (e) {
208
- debug('Error releasing interface: ', e);
209
- }
210
- } else {
211
- // Fallback: try to release all interfaces
212
- const interfaces = scope.device.interfaces;
213
- if (interfaces && interfaces.length > 0) {
214
- for (let interfaceObj of interfaces) {
215
- try {
216
- // Only release if we claimed it (kernel driver was detached)
217
- if (interfaceObj && typeof interfaceObj.release === 'function' && !interfaceObj.isKernelDriverActive()) {
218
- await interfaceObj.release();
219
- }
220
- } catch (e) {
221
- debug('Error releasing interface: ', e);
222
- }
223
- }
224
- }
225
- }
226
- await scope.device.close();
227
- } catch (e) {
228
- debug('Error closing device: ', e);
229
- }
230
- }
231
-
232
- // Clear endpoint before emitting event
233
- scope.endpoint = null;
234
-
235
- // Emit event synchronously - this ensures listeners are called immediately
236
- USB.emit('close', device);
237
- debug('Device Closed!');
238
-
239
- return true;
240
- }
241
-
242
- /**
243
- * Disconnect from the USB device (calls close internally)
244
- * @async
245
- * @returns {Promise<Boolean>} True if disconnection successful
246
- * @fires USB#disconnect
247
- */
248
- USB.disconnect = async () => {
249
- const device = scope.device; // Save device reference before cleanup
250
-
251
- if (scope.device) {
252
- await USB.close().catch(e => { debug(e); return true });
253
- }
254
-
255
- // Clear scope before emitting event
256
- scope.endpoint = null;
257
- scope.device = null;
258
-
259
- // Emit event synchronously - this ensures listeners are called immediately
260
- USB.emit('disconnect', device);
261
- debug('Device Disconnected!');
262
-
263
- return true;
264
- }
265
-
266
- /**
267
- * Write data to the USB printer
268
- * @async
269
- * @param {Buffer} data - Data buffer to send to printer
270
- * @returns {Promise<Boolean>} True if write successful
271
- * @throws {Error} If write fails
272
- */
273
- USB.write = async (data) => {
274
- try {
275
- await scope.endpoint.transfer(data);
276
- return true;
277
- } catch (e) {
278
- throw e;
279
- }
280
- }
281
-
282
- // USB is already an Adapter instance, so export it directly
283
- module.exports = USB;
package/tests/README.md DELETED
@@ -1,67 +0,0 @@
1
- # Tests - EscPos
2
-
3
- This directory contains the test suite for the EscPos library.
4
-
5
- ## Structure
6
-
7
- ```
8
- tests/
9
- ├── unit/ # Isolated unit tests
10
- │ ├── printer/ # Printer class tests
11
- │ ├── adapters/ # Adapter tests (USB/Serial)
12
- │ ├── image/ # Image processing tests
13
- │ └── utils/ # Utility functions tests
14
- └── integration/ # Integration tests
15
- └── printer-flow/ # Complete flow tests
16
- ```
17
-
18
- ## Running Tests
19
-
20
- ```bash
21
- # Run all tests
22
- npm test
23
-
24
- # Run in watch mode
25
- npm run test:watch
26
-
27
- # Run with coverage
28
- npm run test:coverage
29
- ```
30
-
31
- ## Coverage
32
-
33
- The tests cover:
34
- - ✅ Buffer operations
35
- - ✅ Text formatting
36
- - ✅ ESC/POS commands
37
- - ✅ Image processing
38
- - ✅ Barcodes
39
- - ✅ Adapters (with mocks)
40
- - ✅ Complete print flows
41
-
42
- ## Mocks
43
-
44
- The tests use mocks for:
45
- - **USB Adapter**: Mock of `usb` module
46
- - **Serial Adapter**: Mock of `serialport` module
47
- - **Image**: Mock of `get-pixels` module
48
-
49
- This allows running tests without requiring real hardware.
50
-
51
- ## Adding New Tests
52
-
53
- 1. Create the test file in `tests/unit/` or `tests/integration/`
54
- 2. Use the `*.test.js` convention
55
- 3. Follow Jest's describe/it pattern
56
- 4. Use mocks for external dependencies
57
-
58
- ## Example
59
-
60
- ```javascript
61
- describe('MyFeature', () => {
62
- it('should do something', () => {
63
- // test here
64
- });
65
- });
66
- ```
67
-
@@ -1,128 +0,0 @@
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
-