From 1df6154717ccdeca2ff6c609b747e72e6c6ea050 Mon Sep 17 00:00:00 2001 From: Wojtek Naruniec Date: Wed, 7 Aug 2024 21:45:34 +0200 Subject: [PATCH] Add tests for Local importer --- .../import/importer/local-importer.test.ts | 103 ++++++++++++++++++ .../import/validators/local-validator.test.ts | 12 +- 2 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 src/lib/import-export/tests/import/importer/local-importer.test.ts diff --git a/src/lib/import-export/tests/import/importer/local-importer.test.ts b/src/lib/import-export/tests/import/importer/local-importer.test.ts new file mode 100644 index 000000000..d11a41a82 --- /dev/null +++ b/src/lib/import-export/tests/import/importer/local-importer.test.ts @@ -0,0 +1,103 @@ +// To run tests, execute `npm run test -- src/lib/import-export/tests/import/importer/local-importer.test.ts` +import * as fs from 'fs/promises'; +import { lstat, rename } from 'fs-extra'; +import { SiteServer } from '../../../../../site-server'; +import { LocalImporter } from '../../../import/importers'; +import { BackupContents } from '../../../import/types'; + +jest.mock( 'fs/promises' ); +jest.mock( '../../../../../site-server' ); +jest.mock( 'fs-extra' ); + +describe( 'localImporter', () => { + const mockBackupContents: BackupContents = { + extractionDirectory: '/tmp/extracted', + sqlFiles: [ '/tmp/extracted/app/sql/local.sql', '/tmp/extracted/app/sql/local.sql' ], + wpContent: { + uploads: [ '/tmp/extracted/app/public/wp-content/uploads/2023/image.jpg' ], + plugins: [ '/tmp/extracted/app/public/wp-content/plugins/jetpack/jetpack.php' ], + themes: [ '/tmp/extracted/app/public/wp-content/themes/twentytwentyone/style.css' ], + }, + metaFile: '/tmp/extracted/local-site.json', + }; + + const mockStudioSitePath = '/path/to/studio/site'; + const mockStudioSiteId = '123'; + + beforeEach( () => { + jest.clearAllMocks(); + + ( SiteServer.get as jest.Mock ).mockReturnValue( { + details: { path: '/path/to/site' }, + executeWpCliCommand: jest.fn().mockReturnValue( { stderr: null } ), + } ); + + // mock rename + ( rename as jest.Mock ).mockResolvedValue( null ); + + jest.useFakeTimers(); + jest.setSystemTime( new Date( '2024-08-01T12:00:00Z' ) ); + + ( lstat as jest.Mock ).mockResolvedValue( { + isDirectory: jest.fn().mockReturnValue( false ), + } ); + } ); + + afterAll( () => { + jest.useRealTimers(); + } ); + + describe( 'import', () => { + it( 'should copy wp-content files and read meta file', async () => { + const importer = new LocalImporter( mockBackupContents ); + ( fs.mkdir as jest.Mock ).mockResolvedValue( undefined ); + ( fs.copyFile as jest.Mock ).mockResolvedValue( undefined ); + ( fs.readFile as jest.Mock ).mockResolvedValue( + JSON.stringify( { + services: { + php: { + version: '8.2.23', + }, + }, + } ) + ); + + const result = await importer.import( mockStudioSitePath, mockStudioSiteId ); + + expect( result?.meta?.phpVersion ).toBe( '8.2' ); + + expect( fs.mkdir ).toHaveBeenCalled(); + expect( fs.copyFile ).toHaveBeenCalledTimes( 3 ); // One for each wp-content file + expect( fs.readFile ).toHaveBeenCalledWith( '/tmp/extracted/local-site.json', 'utf-8' ); + } ); + + it( 'should handle missing meta file', async () => { + const importer = new LocalImporter( { ...mockBackupContents, metaFile: undefined } ); + ( fs.mkdir as jest.Mock ).mockResolvedValue( undefined ); + ( fs.copyFile as jest.Mock ).mockResolvedValue( undefined ); + + const result = await importer.import( mockStudioSitePath, mockStudioSiteId ); + + expect( result?.meta?.phpVersion ).toBe( undefined ); + + expect( fs.mkdir ).toHaveBeenCalled(); + expect( fs.copyFile ).toHaveBeenCalledTimes( 3 ); + expect( fs.readFile ).not.toHaveBeenCalled(); + } ); + + it( 'should handle JSON parse error in meta file', async () => { + const importer = new LocalImporter( mockBackupContents ); + ( fs.mkdir as jest.Mock ).mockResolvedValue( undefined ); + ( fs.copyFile as jest.Mock ).mockResolvedValue( undefined ); + ( fs.readFile as jest.Mock ).mockResolvedValue( 'Invalid JSON' ); + + await expect( + importer.import( mockStudioSitePath, mockStudioSiteId ) + ).resolves.not.toThrow(); + + expect( fs.mkdir ).toHaveBeenCalled(); + expect( fs.copyFile ).toHaveBeenCalledTimes( 3 ); + expect( fs.readFile ).toHaveBeenCalledWith( '/tmp/extracted/local-site.json', 'utf-8' ); + } ); + } ); +} ); diff --git a/src/lib/import-export/tests/import/validators/local-validator.test.ts b/src/lib/import-export/tests/import/validators/local-validator.test.ts index aae02b2bf..9fa9f3fa3 100644 --- a/src/lib/import-export/tests/import/validators/local-validator.test.ts +++ b/src/lib/import-export/tests/import/validators/local-validator.test.ts @@ -7,7 +7,7 @@ describe( 'LocalValidator', () => { describe( 'canHandle', () => { it( 'should return true for valid Local backup structure', () => { const fileList = [ - 'app/sql/wp_options.sql', + 'app/sql/local.sql', 'app/public/wp-content/uploads/2023/image.jpg', 'app/public/wp-content/plugins/jetpack/jetpack.php', 'app/public/wp-content/themes/twentytwentyone/style.css', @@ -17,7 +17,7 @@ describe( 'LocalValidator', () => { it( 'should not fail if core files exists.', () => { const fileList = [ - 'app/sql/wp_options.sql', + 'app/sql/local.sql', 'app/public/wp-admin/wp-admin.php', 'app/public/wp-admin/about.php', 'app/public/wp-includes/test.php', @@ -37,7 +37,7 @@ describe( 'LocalValidator', () => { describe( 'parseBackupContents', () => { it( 'should correctly parse backup contents', () => { const fileList = [ - 'app/sql/wp_options.sql', + 'app/sql/local.sql', 'app/public/wp-content/uploads/2023/image.jpg', 'app/public/wp-content/plugins/jetpack/jetpack.php', 'app/public/wp-content/themes/twentytwentyone/style.css', @@ -48,7 +48,7 @@ describe( 'LocalValidator', () => { expect( result ).toEqual( { extractionDirectory, - sqlFiles: [ '/tmp/extracted/app/sql/wp_options.sql' ], + sqlFiles: [ '/tmp/extracted/app/sql/local.sql' ], wpContent: { uploads: [ '/tmp/extracted/app/public/wp-content/uploads/2023/image.jpg' ], plugins: [ '/tmp/extracted/app/public/wp-content/plugins/jetpack/jetpack.php' ], @@ -60,7 +60,7 @@ describe( 'LocalValidator', () => { it( 'should ignore files that not needed', () => { const fileList = [ - 'app/sql/wp_options.sql', + 'app/sql/local.sql', 'app/public/wp-admin/wp-admin.php', 'app/public/wp-admin/about.php', 'app/public/wp-includes/test.php', @@ -75,7 +75,7 @@ describe( 'LocalValidator', () => { expect( result ).toEqual( { extractionDirectory, - sqlFiles: [ '/tmp/extracted/app/sql/wp_options.sql' ], + sqlFiles: [ '/tmp/extracted/app/sql/local.sql' ], wpContent: { uploads: [ '/tmp/extracted/app/public/wp-content/uploads/2023/image.jpg' ], plugins: [ '/tmp/extracted/app/public/wp-content/plugins/jetpack/jetpack.php' ],