mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
refactor: email/sms connector test API
This commit is contained in:
parent
e5249e2f8c
commit
98d3f64d46
5 changed files with 78 additions and 97 deletions
|
@ -14,6 +14,7 @@ import useApi from '@/hooks/use-api';
|
|||
import * as styles from './index.module.scss';
|
||||
|
||||
type Props = {
|
||||
connectorId: string;
|
||||
connectorType: Exclude<ConnectorType, ConnectorType.Social>;
|
||||
config?: string;
|
||||
className?: string;
|
||||
|
@ -23,7 +24,7 @@ type FormData = {
|
|||
sendTo: string;
|
||||
};
|
||||
|
||||
const SenderTester = ({ connectorType, config, className }: Props) => {
|
||||
const SenderTester = ({ connectorId, connectorType, config, className }: Props) => {
|
||||
const buttonPosReference = useRef(null);
|
||||
const [showTooltip, setShowTooltip] = useState(false);
|
||||
const [isSubmitting, seIsSubmitting] = useState(false);
|
||||
|
@ -62,7 +63,7 @@ const SenderTester = ({ connectorType, config, className }: Props) => {
|
|||
|
||||
try {
|
||||
await api
|
||||
.post(`/api/connectors/test/${connectorType.toLowerCase()}`, {
|
||||
.post(`/api/connectors/${connectorId}/test`, {
|
||||
json: data,
|
||||
})
|
||||
.json();
|
||||
|
|
|
@ -213,7 +213,7 @@ const ConnectorDetails = () => {
|
|||
/>
|
||||
</FormField>
|
||||
{data.type !== ConnectorType.Social && (
|
||||
<SenderTester connectorType={data.type} config={config} />
|
||||
<SenderTester connectorId={data.id} connectorType={data.type} config={config} />
|
||||
)}
|
||||
{saveError && <div>{saveError}</div>}
|
||||
</div>
|
||||
|
|
|
@ -120,6 +120,7 @@ const Guide = ({ connector, onClose }: Props) => {
|
|||
{!isSocialConnector && (
|
||||
<SenderTester
|
||||
className={styles.tester}
|
||||
connectorId={connectorId}
|
||||
connectorType={connectorType}
|
||||
config={watch('connectorConfigJson')}
|
||||
/>
|
||||
|
|
|
@ -101,51 +101,7 @@ describe('connector route', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('POST /connectors/test/email', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should get email connector and send message', async () => {
|
||||
const mockedEmailConnector: EmailConnectorInstance = {
|
||||
connector: mockConnector,
|
||||
metadata: mockMetadata,
|
||||
validateConfig: jest.fn(),
|
||||
getConfig: jest.fn(),
|
||||
sendMessage: async (
|
||||
address: string,
|
||||
type: keyof EmailMessageTypes,
|
||||
_payload: EmailMessageTypes[typeof type]
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
): Promise<any> => {},
|
||||
};
|
||||
getConnectorInstancesPlaceHolder.mockResolvedValueOnce([mockedEmailConnector]);
|
||||
const sendMessageSpy = jest.spyOn(mockedEmailConnector, 'sendMessage');
|
||||
const response = await connectorRequest
|
||||
.post('/connectors/test/email')
|
||||
.send({ email: 'test@email.com', config: { test: 123 } });
|
||||
expect(sendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(sendMessageSpy).toHaveBeenCalledWith(
|
||||
'test@email.com',
|
||||
'Test',
|
||||
{
|
||||
code: 'email-test',
|
||||
},
|
||||
{ test: 123 }
|
||||
);
|
||||
expect(response).toHaveProperty('statusCode', 204);
|
||||
});
|
||||
|
||||
it('should throw when email connector is not found', async () => {
|
||||
getConnectorInstancesPlaceHolder.mockResolvedValueOnce([]);
|
||||
const response = await connectorRequest
|
||||
.post('/connectors/test/email')
|
||||
.send({ email: 'test@email.com' });
|
||||
expect(response).toHaveProperty('statusCode', 400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /connectors/test/sms', () => {
|
||||
describe('POST /connectors/:id/test', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
@ -170,7 +126,7 @@ describe('connector route', () => {
|
|||
getConnectorInstancesPlaceHolder.mockResolvedValueOnce([mockedSmsConnectorInstance]);
|
||||
const sendMessageSpy = jest.spyOn(mockedSmsConnectorInstance, 'sendMessage');
|
||||
const response = await connectorRequest
|
||||
.post('/connectors/test/sms')
|
||||
.post('/connectors/id/test')
|
||||
.send({ phone: '12345678901', config: { test: 123 } });
|
||||
expect(sendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(sendMessageSpy).toHaveBeenCalledWith(
|
||||
|
@ -184,12 +140,55 @@ describe('connector route', () => {
|
|||
expect(response).toHaveProperty('statusCode', 204);
|
||||
});
|
||||
|
||||
it('should get email connector and send message', async () => {
|
||||
const mockedEmailConnector: EmailConnectorInstance = {
|
||||
connector: mockConnector,
|
||||
metadata: mockMetadata,
|
||||
validateConfig: jest.fn(),
|
||||
getConfig: jest.fn(),
|
||||
sendMessage: async (
|
||||
address: string,
|
||||
type: keyof EmailMessageTypes,
|
||||
_payload: EmailMessageTypes[typeof type]
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
): Promise<any> => {},
|
||||
};
|
||||
getConnectorInstancesPlaceHolder.mockResolvedValueOnce([mockedEmailConnector]);
|
||||
const sendMessageSpy = jest.spyOn(mockedEmailConnector, 'sendMessage');
|
||||
const response = await connectorRequest
|
||||
.post('/connectors/id/test')
|
||||
.send({ email: 'test@email.com', config: { test: 123 } });
|
||||
expect(sendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(sendMessageSpy).toHaveBeenCalledWith(
|
||||
'test@email.com',
|
||||
'Test',
|
||||
{
|
||||
code: 'email-test',
|
||||
},
|
||||
{ test: 123 }
|
||||
);
|
||||
expect(response).toHaveProperty('statusCode', 204);
|
||||
});
|
||||
|
||||
it('should throw when neither phone nor email is provided', async () => {
|
||||
const response = await connectorRequest.post('/connectors/id/test').send({});
|
||||
expect(response).toHaveProperty('statusCode', 400);
|
||||
});
|
||||
|
||||
it('should throw when sms connector is not found', async () => {
|
||||
getConnectorInstancesPlaceHolder.mockResolvedValueOnce([]);
|
||||
const response = await connectorRequest
|
||||
.post('/connectors/test/sms')
|
||||
.post('/connectors/id/test')
|
||||
.send({ phone: '12345678901' });
|
||||
expect(response).toHaveProperty('statusCode', 400);
|
||||
});
|
||||
|
||||
it('should throw when email connector is not found', async () => {
|
||||
getConnectorInstancesPlaceHolder.mockResolvedValueOnce([]);
|
||||
const response = await connectorRequest
|
||||
.post('/connectors/id/test')
|
||||
.send({ email: 'test@email.com' });
|
||||
expect(response).toHaveProperty('statusCode', 400);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -149,25 +149,42 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
|||
);
|
||||
|
||||
router.post(
|
||||
'/connectors/test/email',
|
||||
'/connectors/:id/test',
|
||||
koaGuard({
|
||||
params: object({ id: string().min(1) }),
|
||||
body: object({
|
||||
email: string().regex(emailRegEx),
|
||||
phone: string().regex(phoneRegEx).optional(),
|
||||
email: string().regex(emailRegEx).optional(),
|
||||
config: arbitraryObjectGuard.optional(),
|
||||
}),
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const { email, config } = ctx.guard.body;
|
||||
const {
|
||||
params: { id },
|
||||
body,
|
||||
} = ctx.guard;
|
||||
const { phone, email, config } = body;
|
||||
|
||||
const connectorInstances = await getConnectorInstances();
|
||||
const connector = connectorInstances.find(
|
||||
(connector): connector is EmailConnectorInstance =>
|
||||
connector.metadata.type === ConnectorType.Email
|
||||
);
|
||||
const subject = phone ?? email;
|
||||
assertThat(subject, new RequestError({ code: 'guard.invalid_input' }));
|
||||
|
||||
const connector: SmsConnectorInstance | EmailConnectorInstance | undefined = phone
|
||||
? connectorInstances.find(
|
||||
(connector): connector is SmsConnectorInstance =>
|
||||
connector.metadata.id === id && connector.metadata.type === ConnectorType.SMS
|
||||
)
|
||||
: connectorInstances.find(
|
||||
(connector): connector is EmailConnectorInstance =>
|
||||
connector.metadata.id === id && connector.metadata.type === ConnectorType.Email
|
||||
);
|
||||
|
||||
assertThat(
|
||||
connector,
|
||||
new RequestError({ code: 'connector.not_found', type: ConnectorType.Email })
|
||||
new RequestError({
|
||||
code: 'connector.not_found',
|
||||
type: phone ? ConnectorType.SMS : ConnectorType.Email,
|
||||
})
|
||||
);
|
||||
|
||||
if (config) {
|
||||
|
@ -175,47 +192,10 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
|||
}
|
||||
|
||||
await connector.sendMessage(
|
||||
email,
|
||||
subject,
|
||||
'Test',
|
||||
{
|
||||
code: 'email-test',
|
||||
},
|
||||
config
|
||||
);
|
||||
|
||||
ctx.status = 204;
|
||||
|
||||
return next();
|
||||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/connectors/test/sms',
|
||||
koaGuard({
|
||||
body: object({
|
||||
phone: string().regex(phoneRegEx),
|
||||
config: arbitraryObjectGuard.optional(),
|
||||
}),
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const { phone, config } = ctx.guard.body;
|
||||
|
||||
const connectorInstances = await getConnectorInstances();
|
||||
const connector = connectorInstances.find(
|
||||
(connector): connector is SmsConnectorInstance =>
|
||||
connector.metadata.type === ConnectorType.SMS
|
||||
);
|
||||
|
||||
assertThat(
|
||||
connector,
|
||||
new RequestError({ code: 'connector.not_found', type: ConnectorType.SMS })
|
||||
);
|
||||
|
||||
await connector.sendMessage(
|
||||
phone,
|
||||
'Test',
|
||||
{
|
||||
code: '123456',
|
||||
code: phone ? '123456' : 'email-test',
|
||||
},
|
||||
config
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue