Initial commit: Epson ePOS Node backend + Vue3 UI (printer matricial2)
This commit is contained in:
35
scripts/print_referencia.js
Normal file
35
scripts/print_referencia.js
Normal file
@@ -0,0 +1,35 @@
|
||||
// Print the referencia.jpeg as a raster image via backend Node
|
||||
process.env.PRINTER_HOST = process.env.PRINTER_HOST || '192.168.87.147';
|
||||
process.env.PRINTER_DEVICE_ID = process.env.PRINTER_DEVICE_ID || 'matricial2';
|
||||
process.env.PRINTER_TIMEOUT_MS = process.env.PRINTER_TIMEOUT_MS || '60000';
|
||||
|
||||
process.env.PORT = process.env.PORT || '3002';
|
||||
process.env.TEST_BASE_URL = process.env.TEST_BASE_URL || `http://localhost:${process.env.PORT}`;
|
||||
require('../src/server.js');
|
||||
|
||||
const axios = require('axios');
|
||||
|
||||
async function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
|
||||
|
||||
async function run() {
|
||||
const base = process.env.TEST_BASE_URL || 'http://localhost:3002';
|
||||
await sleep(500);
|
||||
const widths = [576, 512, 448, 384];
|
||||
for (const w of widths) {
|
||||
try {
|
||||
console.log(`Intentando imprimir referencia.jpeg con width=${w}`);
|
||||
const resp = await axios.post(base + '/api/print/image', { path: 'referencia.jpeg', width: w, threshold: 128, mode: 'mono' }, { timeout: 180000 });
|
||||
console.log(resp.data);
|
||||
if (resp.data && resp.data.ok) {
|
||||
console.log('Impresión OK con width=', w);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error al imprimir con width', w, e.message);
|
||||
}
|
||||
await sleep(800);
|
||||
}
|
||||
console.error('No se pudo confirmar OK en ninguna anchura. Revisa el resultado visual o ajusta el umbral.');
|
||||
}
|
||||
|
||||
run().catch((e) => { console.error(e); process.exit(1); });
|
||||
80
scripts/print_template.js
Normal file
80
scripts/print_template.js
Normal file
@@ -0,0 +1,80 @@
|
||||
// Prints from a JSON template spec using backend /api/print
|
||||
// Usage: node scripts/print_template.js templates/referencia.json
|
||||
|
||||
process.env.PRINTER_HOST = process.env.PRINTER_HOST || '192.168.87.147';
|
||||
process.env.PRINTER_DEVICE_ID = process.env.PRINTER_DEVICE_ID || 'matricial2';
|
||||
process.env.PRINTER_TIMEOUT_MS = process.env.PRINTER_TIMEOUT_MS || '60000';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const axios = require('axios');
|
||||
|
||||
// Allow running standalone or with server already running
|
||||
if (!process.env.TEST_BASE_URL) {
|
||||
process.env.PORT = process.env.PORT || '3003';
|
||||
process.env.TEST_BASE_URL = `http://localhost:${process.env.PORT}`;
|
||||
require('../src/server.js');
|
||||
}
|
||||
|
||||
function padRight(str, len) { str = String(str); return str.length >= len ? str.slice(0, len) : str + ' '.repeat(len - str.length); }
|
||||
function padLeft(str, len) { str = String(str); return str.length >= len ? str.slice(0, len) : ' '.repeat(len - str.length) + str; }
|
||||
|
||||
function buildOpsFromSpec(spec) {
|
||||
const ops = [];
|
||||
const widthChars = spec.widthChars || 42; // default receipt width (monospace)
|
||||
const hrChar = spec.hrChar || '-';
|
||||
|
||||
const addLines = (lines, align, options = {}) => {
|
||||
if (align) ops.push({ op: 'textAlign', align });
|
||||
if (options.font) ops.push({ op: 'textFont', font: options.font });
|
||||
if (options.size) ops.push({ op: 'textSize', width: options.size.width, height: options.size.height });
|
||||
if (options.style) ops.push({ op: 'textStyle', ...options.style });
|
||||
for (const ln of lines) ops.push({ op: 'text', value: String(ln) });
|
||||
};
|
||||
|
||||
for (const sec of spec.sections || []) {
|
||||
if (sec.lines) {
|
||||
addLines(sec.lines, sec.align, sec);
|
||||
} else if (sec.hr) {
|
||||
ops.push({ op: 'textAlign', align: 'left' });
|
||||
ops.push({ op: 'text', value: hrChar.repeat(widthChars) });
|
||||
} else if (sec.columns) {
|
||||
const widths = sec.columns.widths || [];
|
||||
const rows = sec.columns.rows || [];
|
||||
for (const row of rows) {
|
||||
const cols = [];
|
||||
for (let i = 0; i < widths.length; i++) {
|
||||
const w = widths[i];
|
||||
const v = row[i] == null ? '' : String(row[i]);
|
||||
// left pad for last col if numeric
|
||||
if (i === widths.length - 1 && /^[0-9$.,\s-]+$/.test(v)) cols.push(padLeft(v, w));
|
||||
else cols.push(padRight(v, w));
|
||||
}
|
||||
ops.push({ op: 'textAlign', align: 'left' });
|
||||
ops.push({ op: 'text', value: cols.join('') });
|
||||
}
|
||||
}
|
||||
if (sec.feedLines) ops.push({ op: 'feedLine', line: sec.feedLines });
|
||||
if (sec.cut) ops.push({ op: 'cut', type: sec.cut });
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const jsonPath = process.argv[2];
|
||||
if (!jsonPath) throw new Error('Template JSON path required');
|
||||
const spec = JSON.parse(fs.readFileSync(path.resolve(jsonPath), 'utf-8'));
|
||||
|
||||
const ops = buildOpsFromSpec(spec);
|
||||
const base = process.env.TEST_BASE_URL;
|
||||
const resp = await axios.post(base + '/api/print', { operations: ops }, { timeout: 180000 });
|
||||
console.log(resp.data);
|
||||
if (!resp.data || resp.data.ok !== true) {
|
||||
throw new Error('Printer did not confirm success.');
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((e) => { console.error(e.message); process.exit(1); });
|
||||
}
|
||||
|
||||
103
scripts/run_tests.js
Normal file
103
scripts/run_tests.js
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
Progressive printer tests via backend endpoints.
|
||||
- Starts the Express server by requiring it
|
||||
- Sends simple -> complex print jobs to matricial2
|
||||
*/
|
||||
process.env.PRINTER_HOST = process.env.PRINTER_HOST || '192.168.87.147';
|
||||
process.env.PRINTER_DEVICE_ID = process.env.PRINTER_DEVICE_ID || 'matricial2';
|
||||
process.env.PRINTER_TIMEOUT_MS = process.env.PRINTER_TIMEOUT_MS || '60000';
|
||||
|
||||
// Start server
|
||||
require('../src/server.js');
|
||||
|
||||
const axios = require('axios');
|
||||
|
||||
async function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
|
||||
|
||||
async function run() {
|
||||
const base = 'http://localhost:3000';
|
||||
const steps = [];
|
||||
|
||||
steps.push({
|
||||
name: 'dryRun minimo',
|
||||
path: '/api/print',
|
||||
body: { operations: [{ op: 'text', value: 'Hola DRYRUN' }], dryRun: true }
|
||||
});
|
||||
|
||||
steps.push({
|
||||
name: 'texto simple',
|
||||
path: '/api/print/text',
|
||||
body: { text: 'Test 1: texto simple', options: { feedLines: 1 } }
|
||||
});
|
||||
|
||||
steps.push({
|
||||
name: 'alineado + corte',
|
||||
path: '/api/print/text',
|
||||
body: { text: 'Test 2: center + cut', options: { align: 'center', feedLines: 1, cut: 'feed' } }
|
||||
});
|
||||
|
||||
steps.push({
|
||||
name: 'fuente y tamaño',
|
||||
path: '/api/print/text',
|
||||
body: { text: 'Test 3: font_b w2 h2', options: { font: 'font_b', size: { width: 2, height: 2 }, style: { em: true } } }
|
||||
});
|
||||
|
||||
steps.push({
|
||||
name: 'lote con feeds',
|
||||
path: '/api/print',
|
||||
body: { operations: [
|
||||
{ op: 'text', value: 'Test 4: linea 1' },
|
||||
{ op: 'feedLine', line: 1 },
|
||||
{ op: 'text', value: 'Test 4: linea 2' }
|
||||
]}
|
||||
});
|
||||
|
||||
steps.push({
|
||||
name: 'barcode EAN13',
|
||||
path: '/api/print',
|
||||
body: { operations: [
|
||||
{ op: 'textAlign', align: 'center' },
|
||||
{ op: 'text', value: 'Test 5: EAN13' },
|
||||
{ op: 'feedLine', line: 1 },
|
||||
{ op: 'barcode', data: '490123456789', type: 'ean13', hri: 'below', width: 3, height: 80 },
|
||||
{ op: 'feedLine', line: 2 }
|
||||
]}
|
||||
});
|
||||
|
||||
steps.push({
|
||||
name: 'QR code',
|
||||
path: '/api/print',
|
||||
body: { operations: [
|
||||
{ op: 'textAlign', align: 'center' },
|
||||
{ op: 'text', value: 'Test 6: QR' },
|
||||
{ op: 'feedLine', line: 1 },
|
||||
{ op: 'qrcode', data: 'https://example.com/test6', model: 'qrcode_model_2', level: 'level_m', size: 6 },
|
||||
{ op: 'feedLine', line: 2 }
|
||||
]}
|
||||
});
|
||||
|
||||
steps.push({
|
||||
name: 'abrir cajon',
|
||||
path: '/api/print/pulse',
|
||||
body: { drawer: 'drawer_1', time: 'pulse_200' }
|
||||
});
|
||||
|
||||
for (const s of steps) {
|
||||
try {
|
||||
console.log(`\n==> ${s.name}`);
|
||||
const resp = await axios.post(base + s.path, s.body, { timeout: 120000 });
|
||||
console.log({ status: resp.status, data: resp.data });
|
||||
if (resp.data && resp.data.ok === false) {
|
||||
console.warn('WARN: backend reported not ok:', resp.data.code || resp.data);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('ERROR in step', s.name, e.message);
|
||||
}
|
||||
await sleep(1000);
|
||||
}
|
||||
|
||||
console.log('\nPruebas completadas.');
|
||||
}
|
||||
|
||||
sleep(500).then(run);
|
||||
|
||||
37
scripts/test_all.js
Normal file
37
scripts/test_all.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// Orchestrator: starts the server and runs separated tests sequentially,
|
||||
// waiting for confirmation (ok: true) from the printer between steps.
|
||||
|
||||
process.env.PRINTER_HOST = process.env.PRINTER_HOST || '192.168.87.147';
|
||||
process.env.PRINTER_DEVICE_ID = process.env.PRINTER_DEVICE_ID || 'matricial2';
|
||||
process.env.PRINTER_TIMEOUT_MS = process.env.PRINTER_TIMEOUT_MS || '60000';
|
||||
process.env.PORT = process.env.PORT || '3001';
|
||||
process.env.TEST_BASE_URL = process.env.TEST_BASE_URL || `http://localhost:${process.env.PORT}`;
|
||||
|
||||
require('../src/server.js');
|
||||
|
||||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
|
||||
async function run() {
|
||||
const tests = [
|
||||
require('./tests/01_text_simple'),
|
||||
require('./tests/02_align_cut'),
|
||||
require('./tests/03_font_size'),
|
||||
require('./tests/04_batch_feeds'),
|
||||
require('./tests/05_barcode'),
|
||||
require('./tests/06_qr'),
|
||||
require('./tests/07_pulse'),
|
||||
];
|
||||
|
||||
await sleep(500); // give server time to bind
|
||||
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
const fn = tests[i];
|
||||
console.log(`\n>>> Running test ${i + 1}`);
|
||||
await fn();
|
||||
await sleep(800); // small gap between prints
|
||||
}
|
||||
|
||||
console.log('\nAll tests completed successfully.');
|
||||
}
|
||||
|
||||
run().catch((e) => { console.error(e); process.exit(1); });
|
||||
14
scripts/tests/01_text_simple.js
Normal file
14
scripts/tests/01_text_simple.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const { post, ensureOk } = require('./common');
|
||||
|
||||
async function run() {
|
||||
const data = await post('/api/print/text', { text: 'Test 1: texto simple', options: { feedLines: 1 } });
|
||||
console.log('01_text_simple ->', data);
|
||||
ensureOk(data, '01_text_simple');
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run().catch((e) => { console.error(e.message); process.exit(1); });
|
||||
}
|
||||
|
||||
module.exports = run;
|
||||
|
||||
14
scripts/tests/02_align_cut.js
Normal file
14
scripts/tests/02_align_cut.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const { post, ensureOk } = require('./common');
|
||||
|
||||
async function run() {
|
||||
const data = await post('/api/print/text', { text: 'Test 2: center + cut', options: { align: 'center', feedLines: 1, cut: 'feed' } });
|
||||
console.log('02_align_cut ->', data);
|
||||
ensureOk(data, '02_align_cut');
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run().catch((e) => { console.error(e.message); process.exit(1); });
|
||||
}
|
||||
|
||||
module.exports = run;
|
||||
|
||||
17
scripts/tests/03_font_size.js
Normal file
17
scripts/tests/03_font_size.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const { post, ensureOk } = require('./common');
|
||||
|
||||
async function run() {
|
||||
const data = await post('/api/print/text', {
|
||||
text: 'Test 3: font_b w2 h2',
|
||||
options: { font: 'font_b', size: { width: 2, height: 2 }, style: { em: true }, feedLines: 1 }
|
||||
});
|
||||
console.log('03_font_size ->', data);
|
||||
ensureOk(data, '03_font_size');
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run().catch((e) => { console.error(e.message); process.exit(1); });
|
||||
}
|
||||
|
||||
module.exports = run;
|
||||
|
||||
21
scripts/tests/04_batch_feeds.js
Normal file
21
scripts/tests/04_batch_feeds.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const { post, ensureOk } = require('./common');
|
||||
|
||||
async function run() {
|
||||
const data = await post('/api/print', {
|
||||
operations: [
|
||||
{ op: 'text', value: 'Test 4: linea 1' },
|
||||
{ op: 'feedLine', line: 1 },
|
||||
{ op: 'text', value: 'Test 4: linea 2' },
|
||||
{ op: 'feedLine', line: 1 }
|
||||
]
|
||||
});
|
||||
console.log('04_batch_feeds ->', data);
|
||||
ensureOk(data, '04_batch_feeds');
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run().catch((e) => { console.error(e.message); process.exit(1); });
|
||||
}
|
||||
|
||||
module.exports = run;
|
||||
|
||||
22
scripts/tests/05_barcode.js
Normal file
22
scripts/tests/05_barcode.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const { post, ensureOk } = require('./common');
|
||||
|
||||
async function run() {
|
||||
const data = await post('/api/print', {
|
||||
operations: [
|
||||
{ op: 'textAlign', align: 'center' },
|
||||
{ op: 'text', value: 'Test 5: EAN13' },
|
||||
{ op: 'feedLine', line: 1 },
|
||||
{ op: 'barcode', data: '490123456789', type: 'ean13', hri: 'below', width: 3, height: 80 },
|
||||
{ op: 'feedLine', line: 2 }
|
||||
]
|
||||
});
|
||||
console.log('05_barcode ->', data);
|
||||
ensureOk(data, '05_barcode');
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run().catch((e) => { console.error(e.message); process.exit(1); });
|
||||
}
|
||||
|
||||
module.exports = run;
|
||||
|
||||
22
scripts/tests/06_qr.js
Normal file
22
scripts/tests/06_qr.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const { post, ensureOk } = require('./common');
|
||||
|
||||
async function run() {
|
||||
const data = await post('/api/print', {
|
||||
operations: [
|
||||
{ op: 'textAlign', align: 'center' },
|
||||
{ op: 'text', value: 'Test 6: QR' },
|
||||
{ op: 'feedLine', line: 1 },
|
||||
{ op: 'qrcode', data: 'https://example.com/test6', model: 'qrcode_model_2', level: 'level_m', size: 6 },
|
||||
{ op: 'feedLine', line: 2 }
|
||||
]
|
||||
});
|
||||
console.log('06_qr ->', data);
|
||||
ensureOk(data, '06_qr');
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run().catch((e) => { console.error(e.message); process.exit(1); });
|
||||
}
|
||||
|
||||
module.exports = run;
|
||||
|
||||
14
scripts/tests/07_pulse.js
Normal file
14
scripts/tests/07_pulse.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const { post, ensureOk } = require('./common');
|
||||
|
||||
async function run() {
|
||||
const data = await post('/api/print/pulse', { drawer: 'drawer_1', time: 'pulse_200' });
|
||||
console.log('07_pulse ->', data);
|
||||
ensureOk(data, '07_pulse');
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run().catch((e) => { console.error(e.message); process.exit(1); });
|
||||
}
|
||||
|
||||
module.exports = run;
|
||||
|
||||
19
scripts/tests/common.js
Normal file
19
scripts/tests/common.js
Normal file
@@ -0,0 +1,19 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const baseURL = process.env.TEST_BASE_URL || 'http://localhost:3000';
|
||||
const client = axios.create({ baseURL, timeout: 120000 });
|
||||
|
||||
async function post(path, body) {
|
||||
const res = await client.post(path, body);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
function ensureOk(data, stepName) {
|
||||
if (!data || data.ok !== true) {
|
||||
const msg = `Printer did not confirm success on step: ${stepName} -> ${JSON.stringify(data)}`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { post, ensureOk };
|
||||
|
||||
Reference in New Issue
Block a user