Skip to content

Commit a8fd9fc

Browse files
committed
mock api endpoints added for testcases
1 parent f26510e commit a8fd9fc

File tree

7 files changed

+602
-19
lines changed

7 files changed

+602
-19
lines changed

lib/gindex.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { type Hawk } from "./core";
44
import {
55
GoogleIndexResponseOptions,
66
GoogleIndexStatusCode,
7+
GoogleJobMediaIndexingPayload,
78
LastStateType,
89
RanStatusFileStructure,
910
SitemapMeta,
@@ -39,22 +40,23 @@ export default class GoogleIndexing {
3940
updatedRoute: string,
4041
): Promise<GoogleIndexResponseOptions> {
4142
try {
42-
const postData = {
43+
const postData: GoogleJobMediaIndexingPayload = {
4344
url: updatedRoute,
4445
type: "URL_UPDATED",
4546
};
4647

47-
const response = await fetch(
48-
"https://indexing.googleapis.com/v3/urlNotifications:publish",
49-
{
50-
method: "POST",
51-
headers: {
52-
"Content-Type": "application/json",
53-
Authorization: `Bearer ${accessToken}`,
54-
},
55-
body: JSON.stringify(postData),
48+
const endpoint = process.env.isdev
49+
? "http://localhost:8080/google-jobmedia-indexing"
50+
: "https://indexing.googleapis.com/v3/urlNotifications:publish";
51+
52+
const response = await fetch(endpoint, {
53+
method: "POST",
54+
headers: {
55+
"Content-Type": "application/json",
56+
Authorization: `Bearer ${accessToken}`,
5657
},
57-
);
58+
body: JSON.stringify(postData),
59+
});
5860

5961
const responseBody = await response.json();
6062

@@ -201,7 +203,13 @@ export default class GoogleIndexing {
201203
siteUrl,
202204
)}/sitemaps/${encodeURIComponent(sitemapURL)}`;
203205

204-
const response = await fetch(apiUrl, {
206+
const endpoint = process.env.isdev
207+
? `http://localhost:8080/webmaster/${encodeURIComponent(
208+
siteUrl,
209+
)}/sitemaps/${encodeURIComponent(sitemapURL)}`
210+
: apiUrl;
211+
212+
const response = await fetch(endpoint, {
205213
method: "PUT",
206214
headers: {
207215
Authorization: `Bearer ${accessToken}`,

lib/indexnow.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { type Hawk } from "./core";
55
import {
66
constants,
77
ftpCredentialOptions,
8+
IndexNowPayload,
89
RanStatusFileStructure,
910
} from "./types";
1011

@@ -138,20 +139,23 @@ export default class IndexNow {
138139
updatedRoutes: string[],
139140
secretkey: string,
140141
): Promise<number> {
141-
const data = JSON.stringify({
142+
const data: IndexNowPayload = {
142143
host: this.#domainName,
143144
key: secretkey,
144145
keyLocation: `https://${this.#domainName}/${secretkey}.txt`,
145146
urlList: updatedRoutes,
146-
});
147+
};
147148

149+
const endpoint = process.env.isdev
150+
? "http://localhost:8080/indexnow"
151+
: "https://api.indexnow.org/IndexNow";
148152
try {
149-
const response = await fetch("https://api.indexnow.org/IndexNow", {
153+
const response = await fetch(endpoint, {
150154
method: "POST",
151155
headers: {
152156
"Content-Type": "application/json; charset=utf-8",
153157
},
154-
body: data,
158+
body: JSON.stringify(data),
155159
});
156160

157161
return response.status; // Return the HTTP status code

lib/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,15 @@ export interface SecretObjectType {
8181
user: string;
8282
pass: string;
8383
}
84+
85+
export interface IndexNowPayload {
86+
host: string;
87+
key: string;
88+
keyLocation: string;
89+
urlList: string[];
90+
}
91+
92+
export interface GoogleJobMediaIndexingPayload {
93+
url: string;
94+
type: "URL_UPDATED";
95+
}

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
"@babel/core": "7.26.0",
7575
"@babel/preset-env": "7.26.0",
7676
"@babel/preset-typescript": "7.26.0",
77+
"@types/express": "^5.0.0",
7778
"@types/jest": "29.5.14",
7879
"@types/jstoxml": "2.0.4",
7980
"@types/luxon": "3.4.2",
@@ -83,6 +84,7 @@
8384
"babel-jest": "29.7.0",
8485
"commander": "^12.1.0",
8586
"eslint": "^9.15.0",
87+
"express": "^4.21.1",
8688
"fast-xml-parser": "^4.5.0",
8789
"jest": "29.7.0",
8890
"ncp": "^2.0.0",

test/mock-api/app.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import express from "express";
2+
import router from "./routes";
3+
4+
const app = express();
5+
6+
app.use(express.json());
7+
app.use(express.urlencoded({ extended: false }));
8+
9+
app.use("/", router);
10+
11+
// error handler
12+
app.use(function (err: any, _req: any, res: any, _next: () => any) {
13+
// set locals, only providing error in development
14+
res.locals.message = err.message;
15+
res.locals.error = err;
16+
17+
// render the error page
18+
res.status(err.status || 500);
19+
res.json({ error: err });
20+
});
21+
22+
const port = 8080;
23+
app.set("port", port);
24+
app.listen(port, () => console.log("Server ready on port:", port));

test/mock-api/routes.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import express from "express";
2+
import {
3+
GoogleJobMediaIndexingPayload,
4+
IndexNowPayload,
5+
} from "../../lib/types";
6+
const router = express.Router();
7+
8+
//PUT
9+
router.put(
10+
"/webmaster/*",
11+
function (req: any, res: any, _next: () => void) {
12+
try {
13+
let [hostname, _, sitemapUrl] = req.url.split("/").slice(-3);
14+
hostname = decodeURIComponent(hostname);
15+
sitemapUrl = decodeURIComponent(sitemapUrl);
16+
17+
const isSameOrginMap = hostname
18+
? sitemapUrl
19+
? hostname.includes(new URL(sitemapUrl).hostname)
20+
: false
21+
: false;
22+
23+
const authtoken = req.headers["authorization"];
24+
const validAuthToken = authtoken && authtoken.length > 150;
25+
26+
if (validAuthToken && isSameOrginMap) {
27+
res.status(200).json({ msg: "Success" });
28+
} else {
29+
res.status(400).json({ msg: "Bad request" });
30+
}
31+
} catch (err) {
32+
res.status(500).json({ msg: err });
33+
}
34+
},
35+
);
36+
37+
//POST
38+
router.post(
39+
"/google-jobmedia-indexing",
40+
function (req: any, res: any, _next: () => void) {
41+
try {
42+
const payload: GoogleJobMediaIndexingPayload = req.body;
43+
44+
const { url, type } = payload;
45+
46+
const validPayload = url
47+
? new URL(url)?.hostname
48+
? type
49+
? true
50+
: false
51+
: false
52+
: false;
53+
54+
const validType = type === "URL_UPDATED";
55+
56+
const authtoken = req.headers["authorization"];
57+
const validAuthToken = authtoken && authtoken.length > 150;
58+
59+
if (validPayload && validType && validAuthToken) {
60+
res.status(200).json({ msg: "Good request" });
61+
} else {
62+
res.status(400).json({ msg: "Required field missing" });
63+
}
64+
} catch (err) {
65+
res.status(500).json({ error: err });
66+
}
67+
},
68+
);
69+
70+
//POST
71+
router.post("/indexnow", function (req: any, res: any, _next: () => void) {
72+
try {
73+
const payload: IndexNowPayload = req.body;
74+
75+
console.log("Received Payload:", payload);
76+
77+
const { host, key, keyLocation, urlList } = payload;
78+
79+
const isNotFound: string | false = !host
80+
? "Host"
81+
: !key
82+
? "Key"
83+
: !keyLocation
84+
? "Key location"
85+
: !urlList
86+
? "Urlist"
87+
: false;
88+
89+
const keyIsValid = key.length >= 32;
90+
91+
const keyLocationIsValid =
92+
(new URL(keyLocation).pathname || false) && //check if its valid url and has path
93+
(new URL(host).hostname || false) && //check if its valid url
94+
keyLocation.includes(host); // check if host intersect with keylocation
95+
96+
const allUrlsAreValid = Array.isArray(urlList) //check if urlist is valid array
97+
? urlList.every((url) => new URL(url).hostname || false) //check if all given url are valid
98+
: false;
99+
100+
if (
101+
!isNotFound &&
102+
keyIsValid &&
103+
keyLocationIsValid &&
104+
allUrlsAreValid
105+
) {
106+
res.status(200).json({ msg: "Good request" });
107+
} else {
108+
res.status(400).json({
109+
msg: "Required field missing or urlList must be array or failed at validation",
110+
});
111+
}
112+
} catch (err) {
113+
res.status(500).json({ error: err });
114+
}
115+
});
116+
117+
export default router;

0 commit comments

Comments
 (0)