import * as fse from "fs-extra" ; import glob from "glob-promise" ; import * as path from "path" ; import pixelmatch from "pixelmatch" ; import sharp from "sharp" ; import * as tmp from "tmp" ; import * as index from "../index" ; describe ( "index" , ( ) => { const fixturesPath = path . join ( __dirname , "fixtures" ) ; const defaultConfig = { icon : { backgroundPath : path . join ( fixturesPath , "example" , "icon-background.svg" ) , foregroundPath : path . join ( fixturesPath , "example" , "icon.svg" ) } , platforms : [ "android" , "ios" ] , force : false } ; let tmpDir ; beforeEach ( ( ) => { tmpDir = tmp . dirSync ( { unsafeCleanup : true } ) ; process . chdir ( tmpDir . name ) ; } ) ; afterEach ( ( ) => { tmpDir . removeCallback ( ) ; } ) ; it ( "generates files from example matching fixtures" , ( ) => testFixture ( "example" , 0.14 ) ) ; it ( "generates files from empty matching fixtures" , ( ) => testFixture ( "empty" , 0.06 ) ) ; it ( "generates files from text matching fixtures" , ( ) => testFixture ( "text" , 0.12 ) , 20 * 1000 ) ; it ( "determines the correct ios asset path" , async ( ) => { await fse . ensureDir ( path . join ( "ios" , "project" , "Images.xcassets" ) ) ; const generator = index . generate ( defaultConfig ) ; const generatedFiles = await readIterable ( generator ) ; expect ( generatedFiles ) . toContain ( "ios/project/Images.xcassets/AppIcon.appiconset/iphone-40@3x.png" ) ; } ) ; it ( "does not re-render files on second run" , async ( ) => { await fse . ensureDir ( path . join ( "ios" , "project" , "Images.xcassets" ) ) ; const firstRunFiles = await readIterable ( index . generate ( defaultConfig ) ) ; const sedonRunFiles = await readIterable ( index . generate ( defaultConfig ) ) ; expect ( firstRunFiles . length ) . toBeGreaterThan ( 0 ) ; expect ( sedonRunFiles . length ) . toBe ( 0 ) ; } ) ; it . only ( "does re-renders files on second run when force is set to true" , async ( ) => { await fse . ensureDir ( path . join ( "ios" , "project" , "Images.xcassets" ) ) ; const firstRunFiles = await readIterable ( index . generate ( defaultConfig ) ) ; const sedonRunFiles = await readIterable ( index . generate ( { ... defaultConfig , force : true } ) ) ; expect ( firstRunFiles . length ) . toBeGreaterThan ( 0 ) ; expect ( sedonRunFiles . length ) . toBeGreaterThan ( 0 ) ; } ) ; async function testFixture ( fixture , threshold ) { const fixtureDir = path . join ( fixturesPath , fixture ) ; const generator = index . generate ( { ... defaultConfig , icon : { backgroundPath : ( await fse . pathExists ( path . join ( fixtureDir , "icon-background.svg" ) ) ) ? path . join ( fixtureDir , "icon-background.svg" ) : undefined , foregroundPath : path . join ( fixtureDir , "icon.svg" ) } , resDirPath : path . join ( tmpDir . name , "android" , "app" , "src" , "main" , "res" ) , iconsetDir : path . join ( tmpDir . name , "ios" , fixture , "Images.xcassets" , "AppIcon.appiconset" ) } ) ; const generatedFiles = [ ] ; for await ( const file of generator ) { const localPath = path . relative ( tmpDir . name , file ) ; const fixturePath = path . join ( fixtureDir , localPath ) ; await expectFilesToEqual ( file , fixturePath , threshold ) ; generatedFiles . push ( localPath ) ; } expect ( generatedFiles . sort ( ) ) . toEqual ( ( await glob ( "*/**" , { cwd : fixtureDir , nodir : true } ) ) . sort ( ) ) ; } } ) ; async function readIterable < Data > ( iterable ) { const values = [ ] ; for await ( const value of iterable ) { values . push ( value ) ; } return values ; } async function expectFilesToEqual ( expected , actual , threshold ) { await expectFileToExist ( expected ) ; await expectFileToExist ( actual ) ; const extension = path . extname ( expected ) ; switch ( extension ) { case ".png" : return expectImagesToEqual ( expected , actual , threshold ) ; case ".json" : return expectJsonToEqual ( expected , actual ) ; case ".xml" : return expectXmlToEqual ( expected , actual ) ; default : return fail ( `Unsupported comparison file type ${ extension }` ) ; } } async function expectFileToExist ( path ) { if ( ! ( await fse . pathExists ( path ) ) ) { fail ( `File did not exist: ${ path }` ) ; } } async function expectXmlToEqual ( expected , actual ) { expect ( await fse . readFile ( expected , "utf-8" ) ) . toEqual ( await fse . readFile ( actual , "utf-8" ) ) ; } async function expectJsonToEqual ( expected , actual ) { expect ( await fse . readJson ( expected ) ) . toEqual ( await fse . readJson ( actual ) ) ; } async function expectImagesToEqual ( expected , actual , threshold ) { const expectedImage = sharp ( expected ) ; const actualImage = sharp ( actual ) ; const expectedData = await expectedImage . ensureAlpha ( ) . raw ( ) . toBuffer ( { resolveWithObject : true } ) ; const actualData = await actualImage . ensureAlpha ( ) . raw ( ) . toBuffer ( { resolveWithObject : true } ) ; expect ( actualData . info ) . toEqual ( expectedData . info ) ; const totalPixelCount = expectedData . info . width * expectedData . info . height ; const mismatchingPixelCount = pixelmatch ( expectedData . data , actualData . data , null , expectedData . info . width , expectedData . info . height , { threshold } ) ; expect ( mismatchingPixelCount / totalPixelCount ) . toBeLessThanOrEqual ( threshold ) ; }