smoketests.test.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. 'use strict';
  2. const chai = require('chai');
  3. const expect = chai.expect;
  4. const Support = require('../integration/support');
  5. const { DataTypes, sql } = require('@sequelize/core');
  6. const sinon = require('sinon');
  7. const dialect = Support.getTestDialect();
  8. describe(Support.getTestDialectTeaser('Smoke Tests'), () => {
  9. describe('getAssociations', () => {
  10. beforeEach(async function () {
  11. this.User = this.sequelize.define('User', { username: DataTypes.STRING });
  12. this.Task = this.sequelize.define('Task', {
  13. title: DataTypes.STRING,
  14. active: DataTypes.BOOLEAN,
  15. });
  16. this.User.belongsToMany(this.Task, { through: 'UserTasks' });
  17. this.Task.belongsToMany(this.User, { through: 'UserTasks' });
  18. await this.sequelize.sync({ force: true });
  19. const [john, task1, task2] = await Promise.all([
  20. this.User.create({ username: 'John' }),
  21. this.Task.create({ title: 'Get rich', active: true }),
  22. this.Task.create({ title: 'Die trying', active: false }),
  23. ]);
  24. this.tasks = [task1, task2];
  25. this.user = john;
  26. return john.setTasks([task1, task2]);
  27. });
  28. it('gets all associated objects with all fields', async function () {
  29. const john = await this.User.findOne({ where: { username: 'John' } });
  30. const tasks = await john.getTasks();
  31. for (const attr of Object.keys(tasks[0].getAttributes())) {
  32. expect(tasks[0]).to.have.property(attr);
  33. }
  34. });
  35. it('supports non primary key attributes for joins (custom through model)', async function () {
  36. const User = this.sequelize.define(
  37. 'User',
  38. {
  39. id: {
  40. type: DataTypes.UUID,
  41. allowNull: false,
  42. primaryKey: true,
  43. defaultValue: sql.uuidV4,
  44. field: 'user_id',
  45. },
  46. userSecondId: {
  47. type: DataTypes.UUID,
  48. allowNull: false,
  49. defaultValue: sql.uuidV4,
  50. field: 'user_second_id',
  51. },
  52. },
  53. {
  54. tableName: 'tbl_user',
  55. indexes: [
  56. {
  57. unique: true,
  58. fields: ['user_second_id'],
  59. },
  60. ],
  61. },
  62. );
  63. const Group = this.sequelize.define(
  64. 'Group',
  65. {
  66. id: {
  67. type: DataTypes.UUID,
  68. allowNull: false,
  69. primaryKey: true,
  70. defaultValue: sql.uuidV4,
  71. field: 'group_id',
  72. },
  73. groupSecondId: {
  74. type: DataTypes.UUID,
  75. allowNull: false,
  76. defaultValue: sql.uuidV4,
  77. field: 'group_second_id',
  78. },
  79. },
  80. {
  81. tableName: 'tbl_group',
  82. indexes: [
  83. {
  84. unique: true,
  85. fields: ['group_second_id'],
  86. },
  87. ],
  88. },
  89. );
  90. const User_has_Group = this.sequelize.define(
  91. 'User_has_Group',
  92. {},
  93. {
  94. tableName: 'tbl_user_has_group',
  95. indexes: [
  96. {
  97. unique: true,
  98. fields: ['UserUserSecondId', 'GroupGroupSecondId'],
  99. },
  100. ],
  101. },
  102. );
  103. User.belongsToMany(Group, { through: User_has_Group, sourceKey: 'userSecondId' });
  104. Group.belongsToMany(User, { through: User_has_Group, sourceKey: 'groupSecondId' });
  105. await this.sequelize.sync({ force: true });
  106. const [user1, user2, group1, group2] = await Promise.all([
  107. User.create(),
  108. User.create(),
  109. Group.create(),
  110. Group.create(),
  111. ]);
  112. await Promise.all([user1.addGroup(group1), user2.addGroup(group2)]);
  113. const [users, groups] = await Promise.all([
  114. User.findAll({
  115. where: {},
  116. include: [Group],
  117. }),
  118. Group.findAll({
  119. include: [User],
  120. }),
  121. ]);
  122. expect(users.length).to.equal(2);
  123. expect(users[0].Groups.length).to.equal(1);
  124. expect(users[1].Groups.length).to.equal(1);
  125. expect(users[0].Groups[0].User_has_Group.UserUserSecondId).to.be.ok;
  126. if (dialect === 'db2') {
  127. expect(users[0].Groups[0].User_has_Group.UserUserSecondId).to.deep.equal(
  128. users[0].userSecondId,
  129. );
  130. } else {
  131. expect(users[0].Groups[0].User_has_Group.UserUserSecondId).to.equal(users[0].userSecondId);
  132. }
  133. expect(users[0].Groups[0].User_has_Group.GroupGroupSecondId).to.be.ok;
  134. if (dialect === 'db2') {
  135. expect(users[0].Groups[0].User_has_Group.GroupGroupSecondId).to.deep.equal(
  136. users[0].Groups[0].groupSecondId,
  137. );
  138. } else {
  139. expect(users[0].Groups[0].User_has_Group.GroupGroupSecondId).to.equal(
  140. users[0].Groups[0].groupSecondId,
  141. );
  142. }
  143. expect(users[1].Groups[0].User_has_Group.UserUserSecondId).to.be.ok;
  144. if (dialect === 'db2') {
  145. expect(users[1].Groups[0].User_has_Group.UserUserSecondId).to.deep.equal(
  146. users[1].userSecondId,
  147. );
  148. } else {
  149. expect(users[1].Groups[0].User_has_Group.UserUserSecondId).to.equal(users[1].userSecondId);
  150. }
  151. expect(users[1].Groups[0].User_has_Group.GroupGroupSecondId).to.be.ok;
  152. if (dialect === 'db2') {
  153. expect(users[1].Groups[0].User_has_Group.GroupGroupSecondId).to.deep.equal(
  154. users[1].Groups[0].groupSecondId,
  155. );
  156. } else {
  157. expect(users[1].Groups[0].User_has_Group.GroupGroupSecondId).to.equal(
  158. users[1].Groups[0].groupSecondId,
  159. );
  160. }
  161. expect(groups.length).to.equal(2);
  162. expect(groups[0].Users.length).to.equal(1);
  163. expect(groups[1].Users.length).to.equal(1);
  164. expect(groups[0].Users[0].User_has_Group.GroupGroupSecondId).to.be.ok;
  165. if (dialect === 'db2') {
  166. expect(groups[0].Users[0].User_has_Group.GroupGroupSecondId).to.deep.equal(
  167. groups[0].groupSecondId,
  168. );
  169. } else {
  170. expect(groups[0].Users[0].User_has_Group.GroupGroupSecondId).to.equal(
  171. groups[0].groupSecondId,
  172. );
  173. }
  174. expect(groups[0].Users[0].User_has_Group.UserUserSecondId).to.be.ok;
  175. if (dialect === 'db2') {
  176. expect(groups[0].Users[0].User_has_Group.UserUserSecondId).to.deep.equal(
  177. groups[0].Users[0].userSecondId,
  178. );
  179. } else {
  180. expect(groups[0].Users[0].User_has_Group.UserUserSecondId).to.equal(
  181. groups[0].Users[0].userSecondId,
  182. );
  183. }
  184. expect(groups[1].Users[0].User_has_Group.GroupGroupSecondId).to.be.ok;
  185. if (dialect === 'db2') {
  186. expect(groups[1].Users[0].User_has_Group.GroupGroupSecondId).to.deep.equal(
  187. groups[1].groupSecondId,
  188. );
  189. } else {
  190. expect(groups[1].Users[0].User_has_Group.GroupGroupSecondId).to.equal(
  191. groups[1].groupSecondId,
  192. );
  193. }
  194. expect(groups[1].Users[0].User_has_Group.UserUserSecondId).to.be.ok;
  195. if (dialect === 'db2') {
  196. expect(groups[1].Users[0].User_has_Group.UserUserSecondId).to.deep.equal(
  197. groups[1].Users[0].userSecondId,
  198. );
  199. } else {
  200. expect(groups[1].Users[0].User_has_Group.UserUserSecondId).to.equal(
  201. groups[1].Users[0].userSecondId,
  202. );
  203. }
  204. });
  205. });
  206. describe('hasAssociations', () => {
  207. beforeEach(function () {
  208. this.Article = this.sequelize.define('Article', {
  209. pk: {
  210. type: DataTypes.INTEGER,
  211. autoIncrement: true,
  212. primaryKey: true,
  213. },
  214. title: DataTypes.STRING,
  215. });
  216. this.Label = this.sequelize.define('Label', {
  217. sk: {
  218. type: DataTypes.INTEGER,
  219. autoIncrement: true,
  220. primaryKey: true,
  221. },
  222. text: DataTypes.STRING,
  223. });
  224. this.ArticleLabel = this.sequelize.define('ArticleLabel');
  225. this.Article.belongsToMany(this.Label, { through: this.ArticleLabel });
  226. this.Label.belongsToMany(this.Article, { through: this.ArticleLabel });
  227. return this.sequelize.sync({ force: true });
  228. });
  229. it('answers false if only some labels have been assigned when passing a primary key instead of an object', async function () {
  230. const [article, label1, label2] = await Promise.all([
  231. this.Article.create({ title: 'Article' }),
  232. this.Label.create({ text: 'Awesomeness' }),
  233. this.Label.create({ text: 'Epicness' }),
  234. ]);
  235. await article.addLabels([label1]);
  236. const result = await article.hasLabels([
  237. label1[this.Label.primaryKeyAttribute],
  238. label2[this.Label.primaryKeyAttribute],
  239. ]);
  240. expect(result).to.be.false;
  241. });
  242. });
  243. describe('countAssociations', () => {
  244. beforeEach(async function () {
  245. this.User = this.sequelize.define('User', {
  246. username: DataTypes.STRING,
  247. });
  248. this.Task = this.sequelize.define('Task', {
  249. title: DataTypes.STRING,
  250. active: DataTypes.BOOLEAN,
  251. });
  252. this.UserTask = this.sequelize.define('UserTask', {
  253. id: {
  254. type: DataTypes.INTEGER,
  255. primaryKey: true,
  256. autoIncrement: true,
  257. },
  258. started: {
  259. type: DataTypes.BOOLEAN,
  260. defaultValue: false,
  261. },
  262. });
  263. this.User.belongsToMany(this.Task, { through: this.UserTask });
  264. this.Task.belongsToMany(this.User, { through: this.UserTask });
  265. await this.sequelize.sync({ force: true });
  266. const [john, task1, task2] = await Promise.all([
  267. this.User.create({ username: 'John' }),
  268. this.Task.create({ title: 'Get rich', active: true }),
  269. this.Task.create({ title: 'Die trying', active: false }),
  270. ]);
  271. this.tasks = [task1, task2];
  272. this.user = john;
  273. return john.setTasks([task1, task2]);
  274. });
  275. it('should count scoped through associations', async function () {
  276. this.User.belongsToMany(this.Task, {
  277. as: 'startedTasks',
  278. through: {
  279. model: this.UserTask,
  280. scope: {
  281. started: true,
  282. },
  283. },
  284. });
  285. for (let i = 0; i < 2; i++) {
  286. await this.user.addTask(await this.Task.create(), {
  287. through: { started: true },
  288. });
  289. }
  290. expect(await this.user.countStartedTasks({})).to.equal(2);
  291. });
  292. });
  293. describe('createAssociations', () => {
  294. it('creates a new associated object', async function () {
  295. const User = this.sequelize.define('User', { username: DataTypes.STRING });
  296. const Task = this.sequelize.define('Task', { title: DataTypes.STRING });
  297. User.belongsToMany(Task, { through: 'UserTasks' });
  298. Task.belongsToMany(User, { through: 'UserTasks' });
  299. await this.sequelize.sync({ force: true });
  300. const task = await Task.create({ title: 'task' });
  301. const createdUser = await task.createUser({ username: 'foo' });
  302. expect(createdUser).to.be.instanceof(User);
  303. expect(createdUser.username).to.equal('foo');
  304. const _users = await task.getUsers();
  305. expect(_users).to.have.length(1);
  306. });
  307. });
  308. describe('belongsTo and hasMany at once', () => {
  309. beforeEach(function () {
  310. this.A = this.sequelize.define('a', { name: DataTypes.STRING });
  311. this.B = this.sequelize.define('b', { name: DataTypes.STRING });
  312. });
  313. describe('target belongs to source', () => {
  314. beforeEach(function () {
  315. this.B.belongsTo(this.A, { as: 'relation1' });
  316. this.A.belongsToMany(this.B, { as: 'relation2', through: 'AB' });
  317. this.B.belongsToMany(this.A, { as: 'relation2', through: 'AB' });
  318. return this.sequelize.sync({ force: true });
  319. });
  320. it('correctly uses bId in A', async function () {
  321. const a1 = this.A.build({ name: 'a1' });
  322. const b1 = this.B.build({ name: 'b1' });
  323. await a1.save();
  324. await b1.save();
  325. await b1.setRelation1(a1);
  326. const b = await this.B.findOne({ where: { name: 'b1' } });
  327. expect(b.relation1Id).to.be.eq(a1.id);
  328. });
  329. });
  330. });
  331. });
  332. describe(Support.getTestDialectTeaser('Instance'), () => {
  333. before(function () {
  334. this.clock = sinon.useFakeTimers();
  335. });
  336. afterEach(function () {
  337. this.clock.reset();
  338. });
  339. after(function () {
  340. this.clock.restore();
  341. });
  342. beforeEach(async function () {
  343. this.User = this.sequelize.define('User', {
  344. username: { type: DataTypes.STRING },
  345. uuidv1: { type: DataTypes.UUID, defaultValue: sql.uuidV1 },
  346. uuidv4: { type: DataTypes.UUID, defaultValue: sql.uuidV4 },
  347. touchedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
  348. aNumber: { type: DataTypes.INTEGER },
  349. bNumber: { type: DataTypes.INTEGER },
  350. aDate: { type: DataTypes.DATE },
  351. validateTest: {
  352. type: DataTypes.INTEGER,
  353. allowNull: true,
  354. validate: { isInt: true },
  355. },
  356. validateCustom: {
  357. type: DataTypes.STRING,
  358. allowNull: true,
  359. validate: { len: { msg: 'Length failed.', args: [1, 20] } },
  360. },
  361. dateAllowNullTrue: {
  362. type: DataTypes.DATE,
  363. allowNull: true,
  364. },
  365. isSuperUser: {
  366. type: DataTypes.BOOLEAN,
  367. defaultValue: false,
  368. },
  369. });
  370. await this.User.sync({ force: true });
  371. });
  372. describe('Escaping', () => {
  373. it('is done properly for special characters', async function () {
  374. // Ideally we should test more: "\0\n\r\b\t\\\'\"\x1a"
  375. // But this causes sqlite to fail and exits the entire test suite immediately
  376. const bio = `${dialect}'"\n`; // Need to add the dialect here so in case of failure I know what DB it failed for
  377. const u1 = await this.User.create({ username: bio });
  378. const u2 = await this.User.findByPk(u1.id);
  379. expect(u2.username).to.equal(bio);
  380. });
  381. });
  382. describe('values', () => {
  383. it('returns all values', async function () {
  384. const User = this.sequelize.define(
  385. 'UserHelper',
  386. {
  387. username: DataTypes.STRING,
  388. },
  389. { timestamps: false, logging: false },
  390. );
  391. await User.sync();
  392. const user = User.build({ username: 'foo' });
  393. expect(user.get({ plain: true })).to.deep.equal({ username: 'foo', id: null });
  394. });
  395. });
  396. describe(Support.getTestDialectTeaser('Model'), () => {
  397. before(function () {
  398. this.clock = sinon.useFakeTimers();
  399. });
  400. after(function () {
  401. this.clock.restore();
  402. });
  403. beforeEach(async function () {
  404. this.User = this.sequelize.define('User', {
  405. username: DataTypes.STRING,
  406. secretValue: DataTypes.STRING,
  407. data: DataTypes.STRING,
  408. intVal: DataTypes.INTEGER,
  409. theDate: DataTypes.DATE,
  410. aBool: DataTypes.BOOLEAN,
  411. });
  412. await this.User.sync({ force: true });
  413. });
  414. describe('save', () => {
  415. it('should map the correct fields when saving instance (#10589)', async function () {
  416. const User = this.sequelize.define('User', {
  417. id3: {
  418. field: 'id',
  419. type: DataTypes.INTEGER,
  420. primaryKey: true,
  421. },
  422. id: {
  423. field: 'id2',
  424. type: DataTypes.INTEGER,
  425. allowNull: false,
  426. },
  427. id2: {
  428. field: 'id3',
  429. type: DataTypes.INTEGER,
  430. allowNull: false,
  431. },
  432. });
  433. await this.sequelize.sync({ force: true });
  434. await User.create({ id3: 94, id: 87, id2: 943 });
  435. const user = await User.findByPk(94);
  436. await user.set('id2', 8877);
  437. await user.save({ id2: 8877 });
  438. expect((await User.findByPk(94)).id2).to.equal(8877);
  439. });
  440. });
  441. });
  442. });