diff --git a/apps/explorer/src/app/components/seconds-ago/seconds-ago.spec.tsx b/apps/explorer/src/app/components/seconds-ago/seconds-ago.spec.tsx
new file mode 100644
index 000000000..cb5022e6e
--- /dev/null
+++ b/apps/explorer/src/app/components/seconds-ago/seconds-ago.spec.tsx
@@ -0,0 +1,25 @@
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+
+import { SecondsAgo } from './index';
+
+describe('Seconds ago', () => {
+ it('should render successfully', () => {
+ const dateInString = Date.now().toString();
+ const { baseElement } = render();
+ expect(baseElement).toBeTruthy();
+ });
+
+ it('should show the correct amount of seconds ago', async () => {
+ const secondsToWait = 2;
+ const dateInString = new Date().toString();
+
+ await new Promise((r) => setTimeout(r, secondsToWait * 1000));
+
+ render();
+
+ expect(
+ screen.getByText(`${secondsToWait} seconds ago`)
+ ).toBeInTheDocument();
+ });
+});
diff --git a/apps/explorer/src/app/components/status-message/status-message.spec.tsx b/apps/explorer/src/app/components/status-message/status-message.spec.tsx
new file mode 100644
index 000000000..77845f645
--- /dev/null
+++ b/apps/explorer/src/app/components/status-message/status-message.spec.tsx
@@ -0,0 +1,10 @@
+import { render } from '@testing-library/react';
+
+import { StatusMessage } from './index';
+
+describe('Status message', () => {
+ it('should render successfully', () => {
+ const { baseElement } = render(test);
+ expect(baseElement).toBeTruthy();
+ });
+});
diff --git a/apps/explorer/src/app/components/table/table.spec.tsx b/apps/explorer/src/app/components/table/table.spec.tsx
new file mode 100644
index 000000000..20b3444aa
--- /dev/null
+++ b/apps/explorer/src/app/components/table/table.spec.tsx
@@ -0,0 +1,122 @@
+import { render } from '@testing-library/react';
+import '@testing-library/jest-dom';
+
+import { Table, TableRow, TableHeader, TableCell } from './index';
+
+describe('Renders all table components', () => {
+ const { container } = render(
+
+ );
+
+ const table = container.querySelector('[data-testid="test-table"]');
+ const tr = container.querySelector('[data-testid="test-tr"]');
+ const th = container.querySelector('[data-testid="test-th"]');
+ const td = container.querySelector('[data-testid="test-td"]');
+
+ expect(table).toBeInTheDocument();
+ expect(th).toBeInTheDocument();
+ expect(tr).toBeInTheDocument();
+ expect(td).toBeInTheDocument();
+});
+
+describe('Table row', () => {
+ it('should include classes based on custom "modifier" prop', () => {
+ const { baseElement: withoutModifier } = render(
+
+ );
+
+ const { baseElement: withModifier } = render(
+
+ );
+
+ const noModifierTr = withoutModifier.querySelector('tr');
+ const modifierTr = withModifier.querySelector('tr');
+ const classNameToCheck = 'border-white-40';
+
+ expect(noModifierTr && !noModifierTr.classList.contains(classNameToCheck));
+ expect(modifierTr && modifierTr.classList.contains(classNameToCheck));
+ });
+});
+
+describe('Table header', () => {
+ it('should accept props i.e. scope="row"', () => {
+ const { baseElement } = render(
+
+ );
+
+ const th = baseElement.querySelector('th');
+
+ expect(th && th.hasAttribute('scope'));
+ });
+
+ it('should include custom class based on scope="row"', () => {
+ const { baseElement: withoutScope } = render(
+
+
+ Without scope attribute
+
+
+ );
+
+ const { baseElement: withScope } = render(
+
+
+ With scope attribute
+
+
+ );
+
+ const withoutScopeTr = withoutScope.querySelector('tr');
+ const withScopeTr = withScope.querySelector('tr');
+ const classNameToCheck = 'text-left';
+
+ expect(
+ withoutScopeTr && !withoutScopeTr.classList.contains(classNameToCheck)
+ );
+ expect(withScopeTr && withScopeTr.classList.contains(classNameToCheck));
+ });
+});
+
+describe('Table cell', () => {
+ it('should include class based on custom "modifier" prop', () => {
+ const { baseElement: withoutModifier } = render(
+
+ );
+
+ const { baseElement: withModifier } = render(
+
+ );
+
+ const noModifierTd = withoutModifier.querySelector('td');
+ const modifierTd = withModifier.querySelector('td');
+ const classNameToCheck = 'py-4';
+
+ expect(noModifierTd && !noModifierTd.classList.contains(classNameToCheck));
+ expect(modifierTd && modifierTd.classList.contains(classNameToCheck));
+ });
+});
diff --git a/apps/explorer/src/app/components/truncate/truncate.spec.tsx b/apps/explorer/src/app/components/truncate/truncate.spec.tsx
new file mode 100644
index 000000000..f24d9084d
--- /dev/null
+++ b/apps/explorer/src/app/components/truncate/truncate.spec.tsx
@@ -0,0 +1,41 @@
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+
+import { TruncateInline } from './truncate';
+
+describe('Truncate', () => {
+ it('should render successfully', () => {
+ const { baseElement } = render(
+
+ );
+
+ expect(baseElement).toBeTruthy();
+ });
+
+ it('it truncates as expected', () => {
+ const test = 'randomstringblahblah';
+ const startChars = 3;
+ const endChars = 3;
+ const expectedString = `${test.slice(0, startChars)}…${test.slice(
+ -endChars
+ )}`;
+
+ render(
+
+ );
+
+ expect(screen.getByText(expectedString)).toBeInTheDocument();
+ });
+
+ it("it doesn't truncate if the string is too short", () => {
+ const test = 'randomstringblahblah';
+ const startChars = test.length;
+ const endChars = test.length;
+
+ render(
+
+ );
+
+ expect(screen.getByText(test)).toBeInTheDocument();
+ });
+});