Ghost/ghost/members-importer/test/importer.test.js
Fabien O'Carroll 75d003816e Fixed the importer from overriding properties
refs https://github.com/TryGhost/Team/issues/1202

When importing we were transforming the CSV and add missing columns to
it before storing it in preparation to perform the import. This resulted
in the missing columns being updated for existing members with blank
data.

We've updated the Members CSV parsing library to take an options list of
columns to include, which then allows imports to not include all of the
default columns.
2021-12-01 17:02:30 +02:00

226 lines
7.1 KiB
JavaScript

// Switch these lines once there are useful utils
// const testUtils = require('./utils');
require('./utils');
const fs = require('fs-extra');
const path = require('path');
const sinon = require('sinon');
const MembersCSVImporter = require('..');
const csvPath = path.join(__dirname, '/fixtures/');
describe('Importer', function () {
let fsWriteSpy;
beforeEach(function () {
fsWriteSpy = sinon.spy(fs, 'writeFile');
});
afterEach(function () {
const writtenFile = fsWriteSpy.args[0][0];
if (writtenFile) {
fs.removeSync(writtenFile);
}
sinon.restore();
});
describe('process', function () {
it('should import a CSV file', async function () {
const defaultProduct = {
id: 'default_product_id'
};
const membersApi = {
productRepository: {
list: async () => {
return {
data: [defaultProduct]
};
}
},
members: {
get: async () => {
return null;
},
create: async (row) => {
return row;
}
}
};
const knexStub = {
transaction: sinon.stub().resolves({
rollback: () => {},
commit: () => {}
})
};
const LabelModelStub = {
findOne: sinon.stub().resolves(null)
};
const importer = new MembersCSVImporter({
storagePath: csvPath,
getTimezone: sinon.stub().returns('UTC'),
getMembersApi: () => membersApi,
sendEmail: sinon.stub(),
isSet: sinon.stub(),
addJob: sinon.stub(),
knex: knexStub,
urlFor: sinon.stub(),
fetchThreshold: async () => 2
});
const result = await importer.process({
pathToCSV: `${csvPath}/single-column-with-header.csv`,
headerMapping: {},
importLabel: {
name: 'test import'
},
user: {
email: 'test@example.com'
},
LabelModel: LabelModelStub
});
should.exist(result.meta);
should.exist(result.meta.stats);
should.exist(result.meta.stats.imported);
result.meta.stats.imported.should.equal(2);
should.exist(result.meta.stats.invalid);
should.equal(result.meta.import_label, null);
// freeze not triggered if the import is not over the threshold
should.exist(result.meta.freeze);
result.meta.freeze.should.be.false();
should.exist(result.meta.originalImportSize);
result.meta.originalImportSize.should.equal(2);
fsWriteSpy.calledOnce.should.be.true();
});
it('should trigger a freeze when over the freeze threshold', async function () {
const defaultProduct = {
id: 'default_product_id'
};
const membersApi = {
productRepository: {
list: async () => {
return {
data: [defaultProduct]
};
}
},
members: {
get: async () => {
return null;
},
create: async (row) => {
return row;
}
}
};
const knexStub = {
transaction: sinon.stub().resolves({
rollback: () => {},
commit: () => {}
})
};
const LabelModelStub = {
findOne: sinon.stub().resolves(null)
};
const importer = new MembersCSVImporter({
storagePath: csvPath,
getTimezone: sinon.stub().returns('UTC'),
getMembersApi: () => membersApi,
sendEmail: sinon.stub(),
isSet: sinon.stub(),
addJob: sinon.stub(),
knex: knexStub,
urlFor: sinon.stub(),
fetchThreshold: async () => 1
});
const result = await importer.process({
pathToCSV: `${csvPath}/single-column-with-header.csv`,
headerMapping: {},
importLabel: {
name: 'test import'
},
user: {
email: 'test@example.com'
},
LabelModel: LabelModelStub
});
should.exist(result.meta);
should.exist(result.meta.stats);
should.exist(result.meta.stats.imported);
result.meta.stats.imported.should.equal(2);
should.exist(result.meta.stats.invalid);
should.equal(result.meta.import_label, null);
should.exist(result.meta.freeze);
result.meta.freeze.should.be.true();
should.exist(result.meta.originalImportSize);
result.meta.originalImportSize.should.equal(2);
fsWriteSpy.calledOnce.should.be.true();
});
});
describe('prepare', function () {
it('processes a basic valid import file for members', async function () {
const membersImporter = new MembersCSVImporter({
storagePath: csvPath,
getTimezone: sinon.stub().returns('UTC'),
getMembersApi: sinon.stub(),
sendEmail: sinon.stub(),
isSet: sinon.stub(),
addJob: sinon.stub(),
knex: sinon.stub(),
urlFor: sinon.stub()
});
const result = await membersImporter.prepare(`${csvPath}/single-column-with-header.csv`);
should.exist(result.id);
result.id.should.match(/\/members-importer\/test\/fixtures\/Members Import/);
result.batches.should.equal(2);
should.exist(result.metadata);
fsWriteSpy.calledOnce.should.be.true();
});
it('Does not include columns not in the original CSV or mapped', async function () {
const membersImporter = new MembersCSVImporter({
storagePath: csvPath,
getTimezone: sinon.stub().returns('UTC'),
getMembersApi: sinon.stub(),
sendEmail: sinon.stub(),
isSet: sinon.stub(),
addJob: sinon.stub(),
knex: sinon.stub(),
urlFor: sinon.stub()
});
await membersImporter.prepare(`${csvPath}/single-column-with-header.csv`);
const fileContents = fsWriteSpy.firstCall.args[1];
fileContents.should.match(/^email,labels\r\n/);
});
});
});