Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wp-now: Add tests that check resulting fs in different modes #339

Merged
merged 20 commits into from
May 16, 2023
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 113 additions & 2 deletions packages/wp-now/src/tests/wp-now.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { inferMode, parseOptions, WPNowMode, WPNowOptions } from '../wp-now';
import startWPNow, {
inferMode,
parseOptions,
WPNowMode,
WPNowOptions,
} from '../wp-now';
import fs from 'fs-extra';
import path from 'path';
import jest from 'jest-mock';
import {
isPluginDirectory,
isThemeDirectory,
isWpContentDirectory,
isWordPressDirectory,
isWordPressDevelopDirectory,
} from '../wp-playground-wordpress';
import jest from 'jest-mock';
import os from 'os';
import crypto from 'crypto';

const exampleDir = __dirname + '/mode-examples';

Expand Down Expand Up @@ -144,3 +151,107 @@ test('isWordPressDevelopDirectory returns false for incomplete WordPress-develop
expect(isWordPressDevelopDirectory(projectPath)).toBe(false);
expect(inferMode(projectPath)).toBe(WPNowMode.INDEX);
});

describe('Test starting different modes', () => {
let tmpExampleDirectory;

/**
* Copy example directory to a temporary directory
*
* Also, silent the console.log() output.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should have a helper function for our log output, so we don't have to suppress the entirety of console.log() in tests?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean adding a condition on the implementation side to use console.log() only if the code is executed outside the test context?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wojtekn Yes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've checked it more, and I found out that jest has a --silent option built-in. We can run this one for CI and normal test execution, and skip the flag if we need to see the output, e.g. for test debugging purposes.

nx test wp-now --silent

That way we wouldn't need to suppress it in tests code, and we wouldn't need to hardcode hiding output for jest context in the tool code.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally, I've used a wrapper for console, which does nothing for the test environment.

*/
beforeEach(() => {
const tmpDirectory = os.tmpdir();
const directoryHash = crypto.randomBytes(20).toString('hex');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a wp-now-tests- prefix to the directoryHash so it's somewhat obvious where these directories are coming from.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, I've added the flag. Note that we are removing the directory in afterEach, so ideally they shouldn't stay in /tmp after tests are executed. It is still a good change for cases in which the test crashes and doesn't run the cleanup method.


tmpExampleDirectory = path.join(tmpDirectory, directoryHash);
fs.ensureDirSync(tmpExampleDirectory);
fs.copySync(exampleDir, tmpExampleDirectory);

jest.spyOn(console, 'log').mockImplementation(() => {});
});

/**
* Remove temporary directory
*/
afterEach(() => {
fs.rmSync(tmpExampleDirectory, { recursive: true, force: true });
});

/**
* Expect that all provided mount point paths are empty directories which are result of file system mounts.
*
* @param mountPaths List of mount point paths that should exist on file system.
* @param projectPath Project path.
*/
const expectEmptyMountPoints = (mountPaths, projectPath) => {
mountPaths.map((relativePath) => {
const fullPath = path.join(projectPath, relativePath);

expect(fs.existsSync(fullPath)).toBe(true);
expect(fs.readdirSync(fullPath)).toEqual([]);
expect(fs.lstatSync(fullPath).isDirectory()).toBe(true);
});
};

/**
* Expect that all required files exist for PHP.
*
* @param requiredFiles List of files that should be accessible by PHP.
* @param documentRoot Document root of the PHP server.
* @param php NodePHP instance.
*/
const expectRequiredFiles = (requiredFiles, documentRoot, php) => {
requiredFiles.map((relativePath) => {
const fullPath = path.join(documentRoot, relativePath);
expect(php.fileExists(fullPath)).toBe(true);
});
};

/**
* Test that startWPNow in "index" mode doesn't change anything in the project directory.
*/
test('startWPNow starts index mode', async () => {
const projectPath = exampleDir + '/index';
const initialProjectContent = fs.readdirSync(projectPath);

const rawOptions: Partial<WPNowOptions> = {
projectPath: projectPath,
};

await startWPNow(rawOptions);

const finalProjectContent = fs.readdirSync(projectPath);
expect(initialProjectContent).toEqual(finalProjectContent);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use explicit assertions in this test?

When the expected results are stored in a variable, it's difficult to evaluate what the test is actually doing.

});

/**
* Test that startWPNow in "wordpress" mode mounts required files and directories, and
* that required files exist for PHP.
*/
test('startWPNow starts wp-content mode', async () => {
const projectPath = path.join(tmpExampleDirectory, 'wp-content');

const rawOptions: Partial<WPNowOptions> = {
projectPath: projectPath,
};

const { php, options: wpNowOptions } = await startWPNow(rawOptions);

const mountPointPaths = [
'database',
'db.php',
'mu-plugins',
'plugins/sqlite-database-integration',
];

expectEmptyMountPoints(mountPointPaths, projectPath);

const requiredFiles = [
'wp-content/db.php',
'wp-content/mu-plugins/0-allow-wp-org.php'
];

expectRequiredFiles(requiredFiles, wpNowOptions.documentRoot, php);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any files we don't expect to be placed in the project directory? Can we add tests for them?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expectEmptyMountPoints function will ensure that mount points are empty directories, so those files can't exist if that part passes. Do you have any other file in mind?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, as an example, that wp-config.php doesn't accidentally exist in the project directory. It'd probably be good to have assertions for each file that wp-now might touch.

});
});