diff --git a/.babelrc.json b/babel.config.json similarity index 100% rename from .babelrc.json rename to babel.config.json diff --git a/frontend/__mocks__/osqueryTableMock.ts b/frontend/__mocks__/osqueryTableMock.ts new file mode 100644 index 000000000..2ebf0c97e --- /dev/null +++ b/frontend/__mocks__/osqueryTableMock.ts @@ -0,0 +1,9 @@ +import { DEFAULT_OSQUERY_TABLE, IOsQueryTable } from "interfaces/osquery_table"; + +const createMockOsqueryTable = ( + overrides?: Partial +): IOsQueryTable => { + return { ...DEFAULT_OSQUERY_TABLE, ...overrides }; +}; + +export default createMockOsqueryTable; diff --git a/frontend/components/side_panels/QuerySidePanel/QuerySidePanel.tests.tsx b/frontend/components/side_panels/QuerySidePanel/QuerySidePanel.tests.tsx new file mode 100644 index 000000000..fcc4124e4 --- /dev/null +++ b/frontend/components/side_panels/QuerySidePanel/QuerySidePanel.tests.tsx @@ -0,0 +1,121 @@ +import React from "react"; +import { noop } from "lodash"; +import { render, screen } from "@testing-library/react"; + +import createMockOsqueryTable from "__mocks__/osqueryTableMock"; +import QuerySidePanel from "./QuerySidePanel"; + +describe("QuerySidePanel - component", () => { + it("renders the query side panel with the correct table selected", () => { + render( + noop} + onClose={noop} + /> + ); + + const tableDropdownText = screen.getByDisplayValue(/users/i); + expect(tableDropdownText).toBeInTheDocument(); + }); + + it("renders platform compatibility", () => { + const { container } = render( + noop} + onClose={noop} + /> + ); + + const platformList = container.getElementsByClassName("platform-list-item"); + const platformCompatibility = screen.getByTestId("compatibility"); + + expect(platformList.length).toBe(4); + expect(platformCompatibility).toHaveTextContent(/macos/i); + expect(platformCompatibility).toHaveTextContent(/windows/i); + expect(platformCompatibility).toHaveTextContent(/linux/i); + expect(platformCompatibility).toHaveTextContent(/chromeos/i); + }); + + it("renders the correct number of columns", () => { + const { container } = render( + noop} + onClose={noop} + /> + ); + + const platformList = container.getElementsByClassName("column-list-item"); + expect(platformList.length).toBe(13); + }); + + it("renders the platform specific column tooltip", () => { + render( + noop} + onClose={noop} + /> + ); + + const tooltip = screen.getByText(/only available on windows/i); + expect(tooltip).toBeInTheDocument(); + }); + + it("render an example", () => { + render( + noop} + onClose={noop} + /> + ); + + const exampleHeader = screen.getByText( + /List users that have interactive access via a shell that isn't false/i + ); + const example = screen.getByText("Example"); + + expect(exampleHeader).toBeInTheDocument(); + expect(example).toBeInTheDocument(); + }); + it("render notes", () => { + render( + noop} + onClose={noop} + /> + ); + + const notesHeader = screen.getByText(/Notes/i); + const notesText = screen.getByText(/This table is being used for testing/i); + + expect(notesHeader).toBeInTheDocument(); + expect(notesText).toBeInTheDocument(); + }); + it("renders a link to the source", () => { + render( + noop} + onClose={noop} + /> + ); + + const text = screen.getByText("Source"); + const icon = screen.queryByTestId("Icon"); + + expect(text).toBeInTheDocument(); + expect(icon).toBeNull(); + expect(text.closest("a")).toHaveAttribute( + "href", + "https://www.fleetdm.com/tables/users" + ); + expect(text.closest("a")).toHaveAttribute("target", "_blank"); + }); +}); diff --git a/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx b/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx index 4ca5111f0..228bb1847 100644 --- a/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx +++ b/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx @@ -44,7 +44,7 @@ const QueryTablePlatforms = ({ platforms }: IQueryTablePlatformsProps) => { }); return ( -
+

Compatible with

    {platformListItems}
diff --git a/frontend/interfaces/osquery_table.ts b/frontend/interfaces/osquery_table.ts index bcfd886ea..14480d5f8 100644 --- a/frontend/interfaces/osquery_table.ts +++ b/frontend/interfaces/osquery_table.ts @@ -44,12 +44,13 @@ export interface IOsQueryTable { notes?: string; } +// Also used for testing export const DEFAULT_OSQUERY_TABLE: IOsQueryTable = { name: "users", description: "Local user accounts (including domain accounts that have logged on locally (Windows)).", url: "https://github.com/osquery/osquery/blob/master/specs/users.table", - platforms: ["darwin", "linux", "windows"], + platforms: ["darwin", "linux", "windows", "chrome"], evented: false, cacheable: false, columns: [ @@ -68,6 +69,7 @@ export const DEFAULT_OSQUERY_TABLE: IOsQueryTable = { hidden: false, required: false, index: false, + platforms: ["macOS", "Windows", "Linux"], }, { name: "uid_signed", @@ -76,6 +78,7 @@ export const DEFAULT_OSQUERY_TABLE: IOsQueryTable = { hidden: false, required: false, index: false, + platforms: ["macOS", "Windows", "Linux"], }, { name: "gid_signed", @@ -84,6 +87,7 @@ export const DEFAULT_OSQUERY_TABLE: IOsQueryTable = { hidden: false, required: false, index: false, + platforms: ["macOS", "Windows", "Linux"], }, { name: "username", @@ -100,6 +104,7 @@ export const DEFAULT_OSQUERY_TABLE: IOsQueryTable = { hidden: false, required: false, index: false, + platforms: ["macOS", "Windows", "Linux"], }, { name: "directory", @@ -108,6 +113,7 @@ export const DEFAULT_OSQUERY_TABLE: IOsQueryTable = { hidden: false, required: false, index: false, + platforms: ["macOS", "Windows", "Linux"], }, { name: "shell", @@ -116,6 +122,7 @@ export const DEFAULT_OSQUERY_TABLE: IOsQueryTable = { hidden: false, required: false, index: false, + platforms: ["macOS", "Windows", "Linux"], }, { name: "uuid", @@ -133,6 +140,7 @@ export const DEFAULT_OSQUERY_TABLE: IOsQueryTable = { hidden: true, required: false, index: false, + platforms: ["Windows"], }, { name: "is_hidden", @@ -141,6 +149,7 @@ export const DEFAULT_OSQUERY_TABLE: IOsQueryTable = { hidden: false, required: false, index: false, + platforms: ["macOS"], }, { name: "pid_with_namespace", @@ -150,5 +159,17 @@ export const DEFAULT_OSQUERY_TABLE: IOsQueryTable = { required: false, index: false, }, + { + name: "email", + description: "Email", + type: "text", + hidden: false, + required: false, + index: false, + platforms: ["chrome"], + }, ], + notes: "", + examples: + "List users that have interactive access via a shell that isn't false.\n```\nSELECT * FROM users WHERE shell!='/usr/bin/false';\n```", }; diff --git a/frontend/test/jest.config.ts b/frontend/test/jest.config.ts index 3afe0dd60..3cc57ec34 100644 --- a/frontend/test/jest.config.ts +++ b/frontend/test/jest.config.ts @@ -1,20 +1,53 @@ import type { Config } from "jest"; +const esModules = [ + "react-markdown", + "vfile", + "vfile-message", + "micromark.+", + "unist-.+", + "unified", + "bail", + "is-plain-obj", + "trough", + "remark-.+", + "mdast-util-.+", + "parse-entities", + "character-entities", + "property-information", + "comma-separated-tokens", + "hast-util-whitespace", + "remark-.+", + "space-separated-tokens", + "decode-named-character-reference", + "ccount", + "escape-string-regexp", + "markdown-table", + "trim-lines", +].join("|"); + const config: Config = { - rootDir: "../", + rootDir: "../../", moduleDirectories: ["node_modules", "frontend"], testEnvironment: "jsdom", moduleNameMapper: { "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": - "/__mocks__/fileMock.js", + "/frontend/__mocks__/fileMock.js", "\\.(css|scss|sass)$": "identity-obj-proxy", + // "react-markdown": + // "/node_modules/react-markdown/react-markdown.min.js", + // "remark-gfm": "/node_modules/remark-gfm/index.js", + // "micromark-extension-gfm": + // "/node_models/micromark-extension-gfm/index.js", }, testMatch: ["**/*tests.[jt]s?(x)"], - setupFilesAfterEnv: ["/test/test-setup.ts"], + setupFilesAfterEnv: ["/frontend/test/test-setup.ts"], clearMocks: true, testEnvironmentOptions: { url: "http://localhost:8080", }, + // transformIgnorePatterns: ["node_modules/(?!react-markdown/)"], + transformIgnorePatterns: [`/node_modules/(?!(${esModules})/)`], }; export default config;