UNPKG

anki-apkg-export

Version:

Generate decks for Anki (spaced repetition software)

119 lines (97 loc) 3.85 kB
import test from 'ava'; import fs from 'fs'; import { execFile } from 'child_process'; import sqlite3 from 'sqlite3'; import isArrayBufferEqual from 'arraybuffer-equal'; import pify from 'pify'; import sinon from 'sinon'; import sortBy from 'lodash.sortby'; import AnkiExport from '../src'; import { addCards, unzipDeckToDir } from './_helpers'; const tmpDir = '/tmp'; const dest = tmpDir + '/result.apkg'; const destUnpacked = tmpDir + '/unpacked_result'; const destUnpackedDb = destUnpacked + '/collection.anki2'; const SEPARATOR = '\u001F'; test.beforeEach(async () => pify(execFile)('rm', ['-rf', dest, destUnpacked])); test('equals to sample', async t => { const now = 1482680798652; const clock = sinon.useFakeTimers(now); const apkg = new AnkiExport('deck-name'); apkg.addMedia('anki.png', fs.readFileSync(__dirname + '/fixtures/anki.png')); apkg.addCard('card #1 front', 'card #1 back', { tags: ['food', 'fruit'] }); apkg.addCard('card #2 front', 'card #2 back'); apkg.addCard('card #3 with image <img src="anki.png" />', 'card #3 back'); const zip = await apkg.save(); fs.writeFileSync(dest, zip, 'binary'); t.true(zip instanceof Buffer); const sampleZip = fs.readFileSync(`${__dirname}/fixtures/output.apkg`); const destZip = fs.readFileSync(dest); t.true(isArrayBufferEqual(destZip.buffer, sampleZip.buffer)); sinon.restore(); clock.restore(); }); test('check internal structure', async t => { // Create deck as in previous example const apkg = new AnkiExport('deck-name'); const cards = [ { front: 'card #1 front', back: 'card #1 back' }, { front: 'card #2 front', back: 'card #2 back' }, { front: 'card #3 with image <img src="anki.png" />', back: 'card #3 back' } ]; addCards(apkg, cards); const zip = await apkg.save(); fs.writeFileSync(dest, zip, 'binary'); // extract dec to tmp directory await unzipDeckToDir(dest, destUnpacked); // analize db via sqlite const db = new sqlite3.Database(destUnpackedDb); const result = await pify(db.all.bind(db))( `SELECT notes.sfld as front, notes.flds as back from cards JOIN notes where cards.nid = notes.id ORDER BY cards.id` ); db.close(); // compare content from just created db with original list of cards const normilizedResult = sortBy( result.map(({ front, back }) => ({ front, back: back.split(SEPARATOR).pop() })), 'front' ); t.deepEqual(normilizedResult, cards); }); test('check internal structure on adding card with tags', async t => { const decFile = `${dest}_with_tags.apkg`; const unzipedDeck = `${destUnpacked}_with_tags`; const apkg = new AnkiExport('deck-name'); const [front1, back1, tags1] = ['Card front side 1', 'Card back side 1', ['some', 'tag', 'tags with multiple words']]; const [front2, back2, tags2] = ['Card front side 2', 'Card back side 2', 'some strin_tags']; const [front3, back3] = ['Card front side 3', 'Card back side 3']; apkg.addCard(front1, back1, { tags: tags1 }); apkg.addCard(front2, back2, { tags: tags2 }); apkg.addCard(front3, back3); const zip = await apkg.save(); fs.writeFileSync(decFile, zip, 'binary'); await unzipDeckToDir(decFile, unzipedDeck); const db = new sqlite3.Database(`${unzipedDeck}/collection.anki2`); const results = await pify(db.all.bind(db))( `SELECT notes.sfld as front, notes.flds as back, notes.tags as tags from cards JOIN notes where cards.nid = notes.id ORDER BY front` ); db.close(); t.deepEqual(results, [ { front: front1, back: `${front1}${SEPARATOR}${back1}`, tags: ' ' + tags1.map(tag => tag.replace(/ /g, '_')).join(' ') + ' ' }, { front: front2, back: `${front2}${SEPARATOR}${back2}`, tags: tags2 }, { front: front3, back: `${front3}${SEPARATOR}${back3}`, tags: '' } ]); });